rnd-19990109-1
[rocksndiamonds.git] / src / editor.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  editor.c                                                *
12 ***********************************************************/
13
14 #include "editor.h"
15 #include "screens.h"
16 #include "tools.h"
17 #include "misc.h"
18 #include "buttons.h"
19 #include "files.h"
20 #include "game.h"
21 #include "tape.h"
22
23 /* positions in the level editor */
24 #define ED_WIN_MB_LEFT_XPOS     7
25 #define ED_WIN_MB_LEFT_YPOS     6
26 #define ED_WIN_LEVELNR_XPOS     77
27 #define ED_WIN_LEVELNR_YPOS     7
28 #define ED_WIN_MB_MIDDLE_XPOS   7
29 #define ED_WIN_MB_MIDDLE_YPOS   258
30 #define ED_WIN_MB_RIGHT_XPOS    77
31 #define ED_WIN_MB_RIGHT_YPOS    258
32
33 /* other constants for the editor */
34 #define ED_SCROLL_NO            0
35 #define ED_SCROLL_LEFT          1
36 #define ED_SCROLL_RIGHT         2
37 #define ED_SCROLL_UP            4
38 #define ED_SCROLL_DOWN          8
39
40 /* screens in the level editor */
41 #define ED_MODE_DRAWING         0
42 #define ED_MODE_INFO            1
43 #define ED_MODE_PROPERTIES      2
44
45 /* how many steps can be cancelled */
46 #define NUM_UNDO_STEPS          (10 + 1)
47
48 /* values for random placement */
49 #define RANDOM_USE_PERCENTAGE   0
50 #define RANDOM_USE_NUM_OBJECTS  1
51
52 /* values for elements with content */
53 #define MAX_ELEMCONT            8
54
55 /* values for the control window */
56 #define ED_CTRL_BUTTONS_GFX_YPOS        236
57 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS    142
58
59 #define ED_CTRL1_BUTTONS_HORIZ  4
60 #define ED_CTRL1_BUTTONS_VERT   4
61 #define ED_CTRL1_BUTTON_XSIZE   22
62 #define ED_CTRL1_BUTTON_YSIZE   22
63 #define ED_CTRL1_BUTTONS_XPOS   6
64 #define ED_CTRL1_BUTTONS_YPOS   6
65 #define ED_CTRL2_BUTTONS_HORIZ  3
66 #define ED_CTRL2_BUTTONS_VERT   2
67 #define ED_CTRL2_BUTTON_XSIZE   30
68 #define ED_CTRL2_BUTTON_YSIZE   20
69 #define ED_CTRL2_BUTTONS_XPOS   5
70 #define ED_CTRL2_BUTTONS_YPOS   100
71 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
72 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
73 #define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
74
75 /* values for properties window */
76 #define ED_PROPERTIES_XPOS      (TILEX - MINI_TILEX/2)
77 /* values for counter gadgets */
78 #define ED_COUNT_VALUE_XOFFSET  5
79 #define ED_COUNT_VALUE_YOFFSET  3
80 #define ED_COUNT_SCORE_XPOS     ED_PROPERTIES_XPOS
81 #define ED_COUNT_SCORE_YPOS     (14 * MINI_TILEY)
82 #define ED_COUNT_ELEMCONT_XPOS  ED_PROPERTIES_XPOS
83 #define ED_COUNT_ELEMCONT_YPOS  (17 * MINI_TILEY)
84
85 /* values for element content drawing areas */
86 #define ED_AREA_ELEMCONT_XPOS   (TILEX)
87 #define ED_AREA_ELEMCONT_YPOS   (10 * TILEY)
88
89 /* values for scrolling gadgets */
90 #define ED_SCROLL_UP_XPOS       (SXSIZE - ED_SCROLLBUTTON_XSIZE)
91 #define ED_SCROLL_UP_YPOS       (0)
92 #define ED_SCROLL_DOWN_XPOS     ED_SCROLL_UP_XPOS
93 #define ED_SCROLL_DOWN_YPOS     (SYSIZE - TILEX - ED_SCROLLBUTTON_YSIZE)
94 #define ED_SCROLL_LEFT_XPOS     (0)
95 #define ED_SCROLL_LEFT_YPOS     (SYSIZE - ED_SCROLLBUTTON_YSIZE)
96 #define ED_SCROLL_RIGHT_XPOS    (SXSIZE - TILEX - ED_SCROLLBUTTON_XSIZE)
97 #define ED_SCROLL_RIGHT_YPOS    ED_SCROLL_LEFT_YPOS
98 #define ED_SCROLL_VERTICAL_XPOS         ED_SCROLL_UP_XPOS
99 #define ED_SCROLL_VERTICAL_YPOS         (ED_SCROLL_UP_YPOS + 20)
100 #define ED_SCROLL_VERTICAL_XSIZE        30
101 #define ED_SCROLL_VERTICAL_YSIZE        (SYSIZE - TILEY - 2 * 20)
102 #define ED_SCROLL_HORIZONTAL_XPOS       (ED_SCROLL_LEFT_XPOS + 30)
103 #define ED_SCROLL_HORIZONTAL_YPOS       (SYSIZE - 30)
104 #define ED_SCROLL_HORIZONTAL_XSIZE      (SXSIZE - TILEX - 2*30)
105 #define ED_SCROLL_HORIZONTAL_YSIZE      30
106
107 /* control button identifiers */
108 #define ED_CTRL_ID_SINGLE_ITEMS         0
109 #define ED_CTRL_ID_CONNECTED_ITEMS      1
110 #define ED_CTRL_ID_LINE                 2
111 #define ED_CTRL_ID_TEXT                 3
112 #define ED_CTRL_ID_RECTANGLE            4
113 #define ED_CTRL_ID_FILLED_BOX           5
114 #define ED_CTRL_ID_WRAP_UP              6
115 #define ED_CTRL_ID_PROPERTIES           7
116 #define ED_CTRL_ID_FLOOD_FILL           8
117 #define ED_CTRL_ID_WRAP_LEFT            9
118 #define ED_CTRL_ID_UNUSED1              10
119 #define ED_CTRL_ID_WRAP_RIGHT           11
120 #define ED_CTRL_ID_RANDOM_PLACEMENT     12
121 #define ED_CTRL_ID_BRUSH                13
122 #define ED_CTRL_ID_WRAP_DOWN            14
123 #define ED_CTRL_ID_PICK_ELEMENT         15
124 #define ED_CTRL_ID_UNDO                 16
125 #define ED_CTRL_ID_INFO                 17
126 #define ED_CTRL_ID_SAVE                 18
127 #define ED_CTRL_ID_CLEAR                19
128 #define ED_CTRL_ID_TEST                 20
129 #define ED_CTRL_ID_EXIT                 21
130
131 /* counter button identifiers */
132 #define ED_CTRL_ID_SCORE_DOWN           22
133 #define ED_CTRL_ID_SCORE_UP             23
134 #define ED_CTRL_ID_ELEMCONT_DOWN        24
135 #define ED_CTRL_ID_ELEMCONT_UP          25
136
137 /* drawing area identifiers */
138 #define ED_CTRL_ID_DRAWING_LEVEL        26
139 #define ED_CTRL_ID_ELEMCONT_0           27
140 #define ED_CTRL_ID_ELEMCONT_7           34
141 #define ED_CTRL_ID_AMOEBA_CONTENT       35
142
143 /* text input identifiers */
144 #define ED_CTRL_ID_LEVEL_NAME           36
145
146 /* gadgets for scrolling of drawing area */
147 #define ED_CTRL_ID_SCROLL_UP            37
148 #define ED_CTRL_ID_SCROLL_DOWN          38
149 #define ED_CTRL_ID_SCROLL_LEFT          39
150 #define ED_CTRL_ID_SCROLL_RIGHT         40
151 #define ED_CTRL_ID_SCROLL_VERTICAL      41
152 #define ED_CTRL_ID_SCROLL_HORIZONTAL    42
153
154 #define ED_NUM_GADGETS                  43
155
156 /* values for counter gadgets */
157 #define ED_COUNTER_SCORE                0
158 #define ED_COUNTER_ELEMCONT             1
159
160 #define ED_NUM_COUNTERBUTTONS           2
161 #define ED_NUM_SCROLLBUTTONS            4
162 #define ED_NUM_SCROLLBARS               2
163
164 /* values for CopyLevelToUndoBuffer() */
165 #define UNDO_IMMEDIATE                  0
166 #define UNDO_ACCUMULATE                 1
167
168 static struct
169 {
170   int x, y;
171   int gadget_id;
172 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
173 {
174   { ED_COUNT_SCORE_XPOS,    ED_COUNT_SCORE_YPOS,    ED_CTRL_ID_SCORE_DOWN },
175   { ED_COUNT_ELEMCONT_XPOS, ED_COUNT_ELEMCONT_YPOS, ED_CTRL_ID_ELEMCONT_DOWN }
176 };
177
178 static struct
179 {
180   int xpos, ypos;
181   int x, y;
182   int gadget_id;
183 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
184 {
185   { ED_BUTTON_UP_XPOS,      ED_BUTTON_UP_YPOS,
186     ED_SCROLL_UP_XPOS,      ED_SCROLL_UP_YPOS,      ED_CTRL_ID_SCROLL_UP },
187   { ED_BUTTON_DOWN_XPOS,    ED_BUTTON_DOWN_YPOS,
188     ED_SCROLL_DOWN_XPOS,    ED_SCROLL_DOWN_YPOS,    ED_CTRL_ID_SCROLL_DOWN },
189   { ED_BUTTON_LEFT_XPOS,    ED_BUTTON_LEFT_YPOS,
190     ED_SCROLL_LEFT_XPOS,    ED_SCROLL_LEFT_YPOS,    ED_CTRL_ID_SCROLL_LEFT },
191   { ED_BUTTON_RIGHT_XPOS,   ED_BUTTON_RIGHT_YPOS,
192     ED_SCROLL_RIGHT_XPOS,   ED_SCROLL_RIGHT_YPOS,   ED_CTRL_ID_SCROLL_RIGHT }
193 };
194
195 static struct
196 {
197   int xpos, ypos;
198   int x, y;
199   int width, height;
200   int type;
201   int gadget_id;
202 } scrollbar_info[ED_NUM_SCROLLBARS] =
203 {
204   { GAME_CONTROL_XPOS,          GAME_CONTROL_YPOS - GAME_BUTTON_YSIZE,
205     ED_SCROLL_VERTICAL_XPOS,    ED_SCROLL_VERTICAL_YPOS,
206     ED_SCROLL_VERTICAL_XSIZE,   ED_SCROLL_VERTICAL_YSIZE,
207     GD_TYPE_SCROLLBAR_VERTICAL,
208     ED_CTRL_ID_SCROLL_VERTICAL },
209   { GAME_CONTROL_XPOS,          GAME_CONTROL_YPOS - GAME_BUTTON_YSIZE,
210     ED_SCROLL_HORIZONTAL_XPOS,  ED_SCROLL_HORIZONTAL_YPOS,
211     ED_SCROLL_HORIZONTAL_XSIZE, ED_SCROLL_HORIZONTAL_YSIZE,
212     GD_TYPE_SCROLLBAR_HORIZONTAL,
213     ED_CTRL_ID_SCROLL_HORIZONTAL },
214 };
215
216
217 /* forward declaration for internal use */
218 static void DrawDrawingWindow();
219 static void DrawPropertiesWindow();
220 static void CopyLevelToUndoBuffer(int);
221 static void HandleControlButtons(struct GadgetInfo *);
222 static void HandleCounterButtons(struct GadgetInfo *);
223 static void HandleDrawingAreas(struct GadgetInfo *);
224 static void HandleTextInputGadgets(struct GadgetInfo *);
225
226 static struct GadgetInfo *level_editor_gadget[ED_NUM_GADGETS];
227 static boolean level_editor_gadgets_created = FALSE;
228
229 static int drawing_function = ED_CTRL_ID_SINGLE_ITEMS;
230 static int last_drawing_function = ED_CTRL_ID_SINGLE_ITEMS;
231 static int properties_element = 0;
232
233 static short ElementContent[MAX_ELEMCONT][3][3];
234 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
235 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
236 static int undo_buffer_position = 0;
237 static int undo_buffer_steps = 0;
238
239 static int random_placement_percentage = 10;
240 static int random_placement_num_objects = 10;
241 #if 0
242 static int random_placement_method = RANDOM_USE_PERCENTAGE;
243 #else
244 static int random_placement_method = RANDOM_USE_NUM_OBJECTS;
245 #endif
246
247 /* pointer to score value */
248 static int *gadget_score_value;
249 static int *gadget_areas_value;
250
251 static int level_xpos,level_ypos;
252 static int edit_mode;
253 static boolean name_typing;
254 static int new_element1 = EL_MAUERWERK;
255 static int new_element2 = EL_LEERRAUM;
256 static int new_element3 = EL_ERDREICH;
257
258 int element_shift = 0;
259
260 int editor_element[] =
261 {
262   EL_CHAR_A + ('B' - 'A'),
263   EL_CHAR_A + ('O' - 'A'),
264   EL_CHAR_A + ('U' - 'A'),
265   EL_CHAR_A + ('L' - 'A'),
266
267   EL_CHAR_MINUS,
268   EL_CHAR_A + ('D' - 'A'),
269   EL_CHAR_A + ('E' - 'A'),
270   EL_CHAR_A + ('R' - 'A'),
271
272   EL_CHAR_A + ('D' - 'A'),
273   EL_CHAR_A + ('A' - 'A'),
274   EL_CHAR_A + ('S' - 'A'),
275   EL_CHAR_A + ('H' - 'A'),
276
277   EL_SPIELFIGUR,
278   EL_LEERRAUM,
279   EL_ERDREICH,
280   EL_BETON,
281
282   EL_FELSBODEN,
283   EL_SIEB2_INAKTIV,
284   EL_AUSGANG_ZU,
285   EL_AUSGANG_AUF,
286
287   EL_EDELSTEIN_BD,
288   EL_BUTTERFLY_O,
289   EL_FIREFLY_O,
290   EL_FELSBROCKEN,
291
292   EL_BUTTERFLY_L,
293   EL_FIREFLY_L,
294   EL_BUTTERFLY_R,
295   EL_FIREFLY_R,
296
297   EL_AMOEBE_BD,
298   EL_BUTTERFLY_U,
299   EL_FIREFLY_U,
300   EL_LEERRAUM,
301
302   EL_CHAR_A + ('E' - 'A'),
303   EL_CHAR_A + ('M' - 'A'),
304   EL_CHAR_A + ('E' - 'A'),
305   EL_CHAR_MINUS,
306
307   EL_CHAR_A + ('R' - 'A'),
308   EL_CHAR_A + ('A' - 'A'),
309   EL_CHAR_A + ('L' - 'A'),
310   EL_CHAR_A + ('D' - 'A'),
311
312   EL_CHAR_A + ('M' - 'A'),
313   EL_CHAR_A + ('I' - 'A'),
314   EL_CHAR_A + ('N' - 'A'),
315   EL_CHAR_A + ('E' - 'A'),
316
317   EL_SPIELER1,
318   EL_SPIELER2,
319   EL_SPIELER3,
320   EL_SPIELER4,
321
322   EL_SPIELFIGUR,
323   EL_LEERRAUM,
324   EL_ERDREICH,
325   EL_FELSBROCKEN,
326
327   EL_BETON,
328   EL_MAUERWERK,
329   EL_FELSBODEN,
330   EL_SIEB_INAKTIV,
331
332   EL_EDELSTEIN,
333   EL_DIAMANT,
334   EL_KOKOSNUSS,
335   EL_BOMBE,
336
337   EL_ERZ_EDEL,
338   EL_ERZ_DIAM,
339   EL_MORAST_LEER,
340   EL_MORAST_VOLL,
341
342   EL_DYNAMIT_AUS,
343   EL_DYNAMIT,
344   EL_AUSGANG_ZU,
345   EL_AUSGANG_AUF,
346
347   EL_MAMPFER,
348   EL_KAEFER_O,
349   EL_FLIEGER_O,
350   EL_ROBOT,
351
352   EL_KAEFER_L,
353   EL_FLIEGER_L,
354   EL_KAEFER_R,
355   EL_FLIEGER_R,
356
357   EL_ABLENK_AUS,
358   EL_KAEFER_U,
359   EL_FLIEGER_U,
360   EL_UNSICHTBAR,
361
362   EL_BADEWANNE1,
363   EL_SALZSAEURE,
364   EL_BADEWANNE2,
365   EL_LEERRAUM,
366
367   EL_BADEWANNE3,
368   EL_BADEWANNE4,
369   EL_BADEWANNE5,
370   EL_LEERRAUM,
371
372   EL_TROPFEN,
373   EL_AMOEBE_TOT,
374   EL_AMOEBE_NASS,
375   EL_AMOEBE_NORM,
376
377   EL_SCHLUESSEL1,
378   EL_SCHLUESSEL2,
379   EL_SCHLUESSEL3,
380   EL_SCHLUESSEL4,
381
382   EL_PFORTE1,
383   EL_PFORTE2,
384   EL_PFORTE3,
385   EL_PFORTE4,
386
387   EL_PFORTE1X,
388   EL_PFORTE2X,
389   EL_PFORTE3X,
390   EL_PFORTE4X,
391
392   EL_CHAR_A + ('M' - 'A'),
393   EL_CHAR_A + ('O' - 'A'),
394   EL_CHAR_A + ('R' - 'A'),
395   EL_CHAR_A + ('E' - 'A'),
396
397   EL_PFEIL_L,
398   EL_PFEIL_R,
399   EL_PFEIL_O,
400   EL_PFEIL_U,
401
402   EL_AMOEBE_VOLL,
403   EL_EDELSTEIN_GELB,
404   EL_EDELSTEIN_ROT,
405   EL_EDELSTEIN_LILA,
406
407   EL_ERZ_EDEL_BD,
408   EL_ERZ_EDEL_GELB,
409   EL_ERZ_EDEL_ROT,
410   EL_ERZ_EDEL_LILA,
411
412   EL_LIFE,
413   EL_PACMAN_O,
414   EL_ZEIT_VOLL,
415   EL_ZEIT_LEER,
416
417   EL_PACMAN_L,
418   EL_MAMPFER2,
419   EL_PACMAN_R,
420   EL_MAUER_LEBT,
421
422   EL_LIFE_ASYNC,
423   EL_PACMAN_U,
424   EL_BIRNE_AUS,
425   EL_BIRNE_EIN,
426
427   EL_DYNABOMB_NR,
428   EL_DYNABOMB_SZ,
429   EL_DYNABOMB_XL,
430   EL_BADEWANNE,
431
432   EL_MAULWURF,
433   EL_PINGUIN,
434   EL_SCHWEIN,
435   EL_DRACHE,
436
437   EL_SONDE,
438   EL_MAUER_X,
439   EL_MAUER_Y,
440   EL_MAUER_XY,
441
442   EL_SPEED_PILL,
443   EL_LEERRAUM,
444   EL_LEERRAUM,
445   EL_LEERRAUM,
446
447   EL_CHAR_A + ('S' - 'A'),
448   EL_CHAR_A + ('O' - 'A'),
449   EL_CHAR_A + ('K' - 'A'),
450   EL_CHAR_A + ('O' - 'A'),
451
452   EL_CHAR_MINUS,
453   EL_CHAR_A + ('B' - 'A'),
454   EL_CHAR_A + ('A' - 'A'),
455   EL_CHAR_A + ('N' - 'A'),
456
457   EL_SOKOBAN_OBJEKT,
458   EL_SOKOBAN_FELD_LEER,
459   EL_SOKOBAN_FELD_VOLL,
460   EL_BETON,
461
462   EL_LEERRAUM,
463   EL_LEERRAUM,
464   EL_LEERRAUM,
465   EL_LEERRAUM,
466
467   EL_CHAR('S'),
468   EL_CHAR('U'),
469   EL_CHAR('P'),
470   EL_CHAR('A'),
471
472   EL_CHAR('P'),
473   EL_CHAR('L'),
474   EL_CHAR('E'),
475   EL_CHAR('X'),
476
477   EL_SP_EMPTY,
478   EL_SP_ZONK,
479   EL_SP_BASE,
480   EL_SP_MURPHY,
481
482   EL_SP_INFOTRON,
483   EL_SP_CHIP_SINGLE,
484   EL_SP_HARD_GRAY,
485   EL_SP_EXIT,
486
487   EL_SP_DISK_ORANGE,
488   EL_SP_PORT1_RIGHT,
489   EL_SP_PORT1_DOWN,
490   EL_SP_PORT1_LEFT,
491
492   EL_SP_PORT1_UP,
493   EL_SP_PORT2_RIGHT,
494   EL_SP_PORT2_DOWN,
495   EL_SP_PORT2_LEFT,
496
497   EL_SP_PORT2_UP,
498   EL_SP_SNIKSNAK,
499   EL_SP_DISK_YELLOW,
500   EL_SP_TERMINAL,
501
502   EL_SP_DISK_RED,
503   EL_SP_PORT_Y,
504   EL_SP_PORT_X,
505   EL_SP_PORT_XY,
506
507   EL_SP_ELECTRON,
508   EL_SP_BUG,
509   EL_SP_CHIP_LEFT,
510   EL_SP_CHIP_RIGHT,
511
512   EL_SP_HARD_BASE1,
513   EL_SP_HARD_GREEN,
514   EL_SP_HARD_BLUE,
515   EL_SP_HARD_RED,
516
517   EL_SP_HARD_YELLOW,
518   EL_SP_HARD_BASE2,
519   EL_SP_HARD_BASE3,
520   EL_SP_HARD_BASE4,
521
522   EL_SP_HARD_BASE5,
523   EL_SP_HARD_BASE6,
524   EL_SP_CHIP_UPPER,
525   EL_SP_CHIP_LOWER,
526
527 /*
528   EL_CHAR_A + ('D' - 'A'),
529   EL_CHAR_A + ('Y' - 'A'),
530   EL_CHAR_A + ('N' - 'A'),
531   EL_CHAR_A + ('A' - 'A'),
532
533   EL_CHAR_A + ('B' - 'A'),
534   EL_CHAR_A + ('L' - 'A'),
535   EL_CHAR_A + ('A' - 'A'),
536   EL_CHAR_A + ('S' - 'A'),
537
538   EL_CHAR_MINUS,
539   EL_CHAR_A + ('T' - 'A'),
540   EL_CHAR_A + ('E' - 'A'),
541   EL_CHAR_A + ('R' - 'A'),
542 */
543
544   EL_LEERRAUM,
545   EL_LEERRAUM,
546   EL_LEERRAUM,
547   EL_LEERRAUM,
548
549   EL_CHAR_AUSRUF,
550   EL_CHAR_ZOLL,
551   EL_CHAR_DOLLAR,
552   EL_CHAR_PROZ,
553
554   EL_CHAR_APOSTR,
555   EL_CHAR_KLAMM1,
556   EL_CHAR_KLAMM2,
557   EL_CHAR_PLUS,
558
559   EL_CHAR_KOMMA,
560   EL_CHAR_MINUS,
561   EL_CHAR_PUNKT,
562   EL_CHAR_SLASH,
563
564   EL_CHAR_0 + 0,
565   EL_CHAR_0 + 1,
566   EL_CHAR_0 + 2,
567   EL_CHAR_0 + 3,
568
569   EL_CHAR_0 + 4,
570   EL_CHAR_0 + 5,
571   EL_CHAR_0 + 6,
572   EL_CHAR_0 + 7,
573
574   EL_CHAR_0 + 8,
575   EL_CHAR_0 + 9,
576   EL_CHAR_DOPPEL,
577   EL_CHAR_SEMIKL,
578
579   EL_CHAR_LT,
580   EL_CHAR_GLEICH,
581   EL_CHAR_GT,
582   EL_CHAR_FRAGE,
583
584   EL_CHAR_AT,
585   EL_CHAR_A + 0,
586   EL_CHAR_A + 1,
587   EL_CHAR_A + 2,
588
589   EL_CHAR_A + 3,
590   EL_CHAR_A + 4,
591   EL_CHAR_A + 5,
592   EL_CHAR_A + 6,
593
594   EL_CHAR_A + 7,
595   EL_CHAR_A + 8,
596   EL_CHAR_A + 9,
597   EL_CHAR_A + 10,
598
599   EL_CHAR_A + 11,
600   EL_CHAR_A + 12,
601   EL_CHAR_A + 13,
602   EL_CHAR_A + 14,
603
604   EL_CHAR_A + 15,
605   EL_CHAR_A + 16,
606   EL_CHAR_A + 17,
607   EL_CHAR_A + 18,
608
609   EL_CHAR_A + 19,
610   EL_CHAR_A + 20,
611   EL_CHAR_A + 21,
612   EL_CHAR_A + 22,
613
614   EL_CHAR_A + 23,
615   EL_CHAR_A + 24,
616   EL_CHAR_A + 25,
617   EL_CHAR_AE,
618
619   EL_CHAR_OE,
620   EL_CHAR_UE,
621   EL_CHAR_COPY,
622   EL_LEERRAUM
623 };
624 int elements_in_list = sizeof(editor_element)/sizeof(int);
625
626 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
627 {
628   int x,y;
629   int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
630   int dy = (scroll == ED_SCROLL_UP   ? -1 : scroll == ED_SCROLL_DOWN  ? 1 : 0);
631
632   XCopyArea(display, drawto, drawto, gc,
633             SX + (dx == -1 ? MINI_TILEX : 0),
634             SY + (dy == -1 ? MINI_TILEY : 0),
635             (ED_FIELDX * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
636             (ED_FIELDY * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
637             SX + (dx == +1 ? MINI_TILEX : 0),
638             SY + (dy == +1 ? MINI_TILEY : 0));
639   if (dx)
640   {
641     x = (dx == 1 ? 0 : ED_FIELDX - 1);
642     for(y=0; y<ED_FIELDY; y++)
643       DrawMiniElementOrWall(x, y, from_x, from_y);
644   }
645   else if (dy)
646   {
647     y = (dy == 1 ? 0 : ED_FIELDY - 1);
648     for(x=0; x<ED_FIELDX; x++)
649       DrawMiniElementOrWall(x, y, from_x, from_y);
650   }
651
652   redraw_mask |= REDRAW_FIELD;
653   BackToFront();
654 }
655
656 void InitLevelEditorGadgets()
657 {
658   int i;
659
660   for (i=0; i<ED_NUM_GADGETS; i++)
661     level_editor_gadget[i] = NULL;
662 }
663
664 static void CreateControlButtons()
665 {
666   Pixmap gd_pixmap = pix[PIX_DOOR];
667   struct GadgetInfo *gi;
668   unsigned long event_mask;
669   int i;
670
671   /* create toolbox buttons */
672   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
673   {
674     int id = i;
675     int width, height;
676     int gd_xoffset, gd_yoffset;
677     int gd_x1, gd_x2, gd_y1, gd_y2;
678     int button_type;
679     int radio_button_nr;
680     boolean radio_button_pressed;
681
682     if (id == ED_CTRL_ID_SINGLE_ITEMS ||
683         id == ED_CTRL_ID_CONNECTED_ITEMS ||
684         id == ED_CTRL_ID_LINE ||
685         id == ED_CTRL_ID_TEXT ||
686         id == ED_CTRL_ID_RECTANGLE ||
687         id == ED_CTRL_ID_FILLED_BOX ||
688         id == ED_CTRL_ID_FLOOD_FILL ||
689         id == ED_CTRL_ID_BRUSH ||
690         id == ED_CTRL_ID_PICK_ELEMENT)
691     {
692       button_type = GD_TYPE_RADIO_BUTTON;
693       radio_button_nr = 1;
694       radio_button_pressed = (id == drawing_function ? TRUE : FALSE);
695       event_mask = GD_EVENT_PRESSED;
696     }
697     else
698     {
699       button_type = GD_TYPE_NORMAL_BUTTON;
700       radio_button_nr = 0;
701       radio_button_pressed = FALSE;
702
703       if (id == ED_CTRL_ID_WRAP_LEFT ||
704           id == ED_CTRL_ID_WRAP_RIGHT ||
705           id == ED_CTRL_ID_WRAP_UP ||
706           id == ED_CTRL_ID_WRAP_DOWN)
707         event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
708       else
709         event_mask = GD_EVENT_RELEASED;
710     }
711
712     if (id < ED_NUM_CTRL1_BUTTONS)
713     {
714       int x = i % ED_CTRL1_BUTTONS_HORIZ;
715       int y = i / ED_CTRL1_BUTTONS_HORIZ;
716
717       gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
718       gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
719       width = ED_CTRL1_BUTTON_XSIZE;
720       height = ED_CTRL1_BUTTON_YSIZE;
721     }
722     else
723     {
724       int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
725       int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
726
727       gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
728       gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
729       width = ED_CTRL2_BUTTON_XSIZE;
730       height = ED_CTRL2_BUTTON_YSIZE;
731     }
732
733     gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
734     gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
735     gd_y1  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_GFX_YPOS + gd_yoffset;
736     gd_y2  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
737
738     gi = CreateGadget(GDI_CUSTOM_ID, id,
739                       GDI_X, EX + gd_xoffset,
740                       GDI_Y, EY + gd_yoffset,
741                       GDI_WIDTH, width,
742                       GDI_HEIGHT, height,
743                       GDI_TYPE, button_type,
744                       GDI_STATE, GD_BUTTON_UNPRESSED,
745                       GDI_RADIO_NR, radio_button_nr,
746                       GDI_RADIO_PRESSED, radio_button_pressed,
747                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
748                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
749                       GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
750                       GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
751                       GDI_EVENT_MASK, event_mask,
752                       GDI_CALLBACK, HandleControlButtons,
753                       GDI_END);
754
755     if (gi == NULL)
756       Error(ERR_EXIT, "cannot create gadget");
757
758     level_editor_gadget[id] = gi;
759   }
760
761   /* create buttons for scrolling of drawing area */
762   for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
763   {
764     int id = scrollbutton_info[i].gadget_id;
765     int gd_x1, gd_x2, gd_y;
766
767     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
768
769     gd_x1 = DOOR_GFX_PAGEX6 + scrollbutton_info[i].xpos;
770     gd_x2 = DOOR_GFX_PAGEX5 + scrollbutton_info[i].xpos;
771     gd_y  = DOOR_GFX_PAGEY2 + scrollbutton_info[i].ypos;
772
773     gi = CreateGadget(GDI_CUSTOM_ID, id,
774                       GDI_X, SX + scrollbutton_info[i].x,
775                       GDI_Y, SY + scrollbutton_info[i].y,
776                       GDI_WIDTH, ED_SCROLLBUTTON_XSIZE,
777                       GDI_HEIGHT, ED_SCROLLBUTTON_YSIZE,
778                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
779                       GDI_STATE, GD_BUTTON_UNPRESSED,
780                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
781                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
782                       GDI_EVENT_MASK, event_mask,
783                       GDI_CALLBACK, HandleControlButtons,
784                       GDI_END);
785
786     if (gi == NULL)
787       Error(ERR_EXIT, "cannot create gadget");
788
789     level_editor_gadget[id] = gi;
790   }
791 }
792
793 static void CreateCounterButtons()
794 {
795   int i, j;
796
797   for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
798   {
799     for (j=0; j<2; j++)
800     {
801       Pixmap gd_pixmap = pix[PIX_DOOR];
802       struct GadgetInfo *gi;
803       int id = counterbutton_info[i].gadget_id + j;
804       int gd_xoffset;
805       int gd_x1, gd_x2, gd_y;
806       unsigned long event_mask;
807
808       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
809
810       gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
811       gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
812       gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
813       gd_y  = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
814
815       gi = CreateGadget(GDI_CUSTOM_ID, id,
816                         GDI_X, SX + counterbutton_info[i].x + gd_xoffset,
817                         GDI_Y, SY + counterbutton_info[i].y,
818                         GDI_WIDTH, ED_BUTTON_COUNT_XSIZE,
819                         GDI_HEIGHT, ED_BUTTON_COUNT_YSIZE,
820                         GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
821                         GDI_STATE, GD_BUTTON_UNPRESSED,
822                         GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
823                         GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
824                         GDI_EVENT_MASK, event_mask,
825                         GDI_CALLBACK, HandleCounterButtons,
826                         GDI_END);
827
828       if (gi == NULL)
829         Error(ERR_EXIT, "cannot create gadget");
830
831       level_editor_gadget[id] = gi;
832     }
833   }
834 }
835
836 static void CreateDrawingAreas()
837 {
838   struct GadgetInfo *gi;
839   unsigned long event_mask;
840   int id;
841   int i;
842
843   event_mask =
844     GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
845     GD_EVENT_OFF_BORDERS;
846
847   /* one for the level drawing area ... */
848   id = ED_CTRL_ID_DRAWING_LEVEL;
849   gi = CreateGadget(GDI_CUSTOM_ID, id,
850                     GDI_X, SX,
851                     GDI_Y, SY,
852
853                     /*
854                     GDI_WIDTH, SXSIZE,
855                     GDI_HEIGHT, SYSIZE,
856                     */
857
858                     GDI_TYPE, GD_TYPE_DRAWING_AREA,
859                     GDI_AREA_SIZE, ED_FIELDX, ED_FIELDY,
860                     GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
861                     GDI_EVENT_MASK, event_mask,
862                     GDI_CALLBACK, HandleDrawingAreas,
863                     GDI_END);
864
865   if (gi == NULL)
866     Error(ERR_EXIT, "cannot create gadget");
867
868   level_editor_gadget[id] = gi;
869
870   /* ... up to eight areas for element content ... */
871   for (i=0; i<MAX_ELEMCONT; i++)
872   {
873     int gx = SX + ED_AREA_ELEMCONT_XPOS + 5 * (i % 4) * MINI_TILEX;
874     int gy = SX + ED_AREA_ELEMCONT_YPOS + 6 * (i / 4) * MINI_TILEY;
875
876     id = ED_CTRL_ID_ELEMCONT_0 + i;
877     gi = CreateGadget(GDI_CUSTOM_ID, id,
878                       GDI_X, gx,
879                       GDI_Y, gy,
880                       GDI_WIDTH, 3 * MINI_TILEX,
881                       GDI_HEIGHT, 3 * MINI_TILEY,
882                       GDI_TYPE, GD_TYPE_DRAWING_AREA,
883                       GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
884                       GDI_EVENT_MASK, event_mask,
885                       GDI_CALLBACK, HandleDrawingAreas,
886                       GDI_END);
887
888     if (gi == NULL)
889       Error(ERR_EXIT, "cannot create gadget");
890
891     level_editor_gadget[id] = gi;
892   }
893
894   /* ... and one for the amoeba content */
895   id = ED_CTRL_ID_AMOEBA_CONTENT;
896   gi = CreateGadget(GDI_CUSTOM_ID, id,
897                     GDI_X, SX + ED_AREA_ELEMCONT_XPOS,
898                     GDI_Y, SY + ED_AREA_ELEMCONT_YPOS,
899                     GDI_WIDTH, MINI_TILEX,
900                     GDI_HEIGHT, MINI_TILEY,
901                     GDI_TYPE, GD_TYPE_DRAWING_AREA,
902                     GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
903                     GDI_EVENT_MASK, event_mask,
904                     GDI_CALLBACK, HandleDrawingAreas,
905                     GDI_END);
906
907   if (gi == NULL)
908     Error(ERR_EXIT, "cannot create gadget");
909
910   level_editor_gadget[id] = gi;
911 }
912
913 static void CreateTextInputGadgets()
914 {
915   Pixmap gd_pixmap = pix[PIX_DOOR];
916   int gd_x, gd_y;
917   struct GadgetInfo *gi;
918   unsigned long event_mask;
919   int id;
920
921   gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
922   gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
923   event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
924
925   /* text input gadget for the level name */
926   id = ED_CTRL_ID_LEVEL_NAME;
927   gi = CreateGadget(GDI_CUSTOM_ID, id,
928                     GDI_X, SX + ED_COUNT_ELEMCONT_XPOS,
929                     GDI_Y, SY + ED_AREA_ELEMCONT_YPOS + 3 * TILEX,
930                     GDI_TYPE, GD_TYPE_TEXTINPUT,
931                     GDI_TEXT_VALUE, level.name,
932                     GDI_TEXT_SIZE, 30,
933                     GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
934                     GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
935                     GDI_DESIGN_BORDER, 3,
936                     GDI_EVENT_MASK, event_mask,
937                     GDI_CALLBACK, HandleTextInputGadgets,
938                     GDI_END);
939
940   if (gi == NULL)
941     Error(ERR_EXIT, "cannot create gadget");
942
943   level_editor_gadget[id] = gi;
944 }
945
946 static void CreateScrollbarGadgets()
947 {
948   int i;
949
950   for (i=0; i<ED_NUM_SCROLLBARS; i++)
951   {
952     int id = scrollbar_info[i].gadget_id;
953     Pixmap gd_pixmap = pix[PIX_DOOR];
954     int gd_x1, gd_x2, gd_y;
955     struct GadgetInfo *gi;
956     int items_max, items_visible, item_position;
957     unsigned long event_mask;
958
959     if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
960     {
961       items_max = lev_fieldx + 2;
962       items_visible = ED_FIELDX;
963       item_position = 0;
964     }
965     else
966     {
967       items_max = lev_fieldy + 2;
968       items_visible = ED_FIELDY;
969       item_position = 0;
970     }
971
972     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
973
974     gd_x1 = DOOR_GFX_PAGEX4 + scrollbar_info[i].xpos;
975     gd_x2 = DOOR_GFX_PAGEX3 + scrollbar_info[i].xpos;
976     gd_y  = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
977
978     gi = CreateGadget(GDI_CUSTOM_ID, id,
979                       GDI_X, SX + scrollbar_info[i].x,
980                       GDI_Y, SY + scrollbar_info[i].y,
981                       GDI_WIDTH, scrollbar_info[i].width,
982                       GDI_HEIGHT, scrollbar_info[i].height,
983                       GDI_TYPE, scrollbar_info[i].type,
984                       GDI_SCROLLBAR_ITEMS_MAX, items_max,
985                       GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
986                       GDI_SCROLLBAR_ITEM_POSITION, item_position,
987                       GDI_STATE, GD_BUTTON_UNPRESSED,
988                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
989                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
990                       GDI_DESIGN_BORDER, 3,
991                       GDI_EVENT_MASK, event_mask,
992                       GDI_CALLBACK, HandleControlButtons,
993                       GDI_END);
994
995     if (gi == NULL)
996       Error(ERR_EXIT, "cannot create gadget");
997
998     level_editor_gadget[id] = gi;
999   }
1000 }
1001
1002 static void CreateLevelEditorGadgets()
1003 {
1004   if (level_editor_gadgets_created)
1005     return;
1006
1007   CreateControlButtons();
1008   CreateCounterButtons();
1009   CreateDrawingAreas();
1010   CreateTextInputGadgets();
1011   CreateScrollbarGadgets();
1012
1013   level_editor_gadgets_created = TRUE;
1014 }
1015
1016 static void MapControlButtons()
1017 {
1018   int i;
1019
1020   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
1021     MapGadget(level_editor_gadget[i]);
1022 }
1023
1024 static void MapCounterButtons(int id)
1025 {
1026   int i;
1027
1028   for (i=0; i<2; i++)
1029     MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id + i]);
1030 }
1031
1032 static void MapDrawingArea(int id)
1033 {
1034   MapGadget(level_editor_gadget[id]);
1035 }
1036
1037 static void MapTextInputGadget(int id)
1038 {
1039   MapGadget(level_editor_gadget[id]);
1040 }
1041
1042 static void MapMainDrawingArea()
1043 {
1044   int i;
1045
1046   for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
1047     MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
1048
1049   for (i=0; i<ED_NUM_SCROLLBARS; i++)
1050     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
1051
1052   MapDrawingArea(ED_CTRL_ID_DRAWING_LEVEL);
1053 }
1054
1055 static void UnmapDrawingArea(int id)
1056 {
1057   UnmapGadget(level_editor_gadget[id]);
1058 }
1059
1060 void UnmapLevelEditorWindowGadgets()
1061 {
1062   int i;
1063
1064   for (i=ED_NUM_CTRL_BUTTONS; i<ED_NUM_GADGETS; i++)
1065     UnmapGadget(level_editor_gadget[i]);
1066 }
1067
1068 void UnmapLevelEditorGadgets()
1069 {
1070   int i;
1071
1072   for (i=0; i<ED_NUM_GADGETS; i++)
1073     UnmapGadget(level_editor_gadget[i]);
1074 }
1075
1076 void DrawLevelEd()
1077 {
1078   int i, x, y, graphic;
1079
1080   level_xpos = -1;
1081   level_ypos = -1;
1082   edit_mode = ED_MODE_DRAWING;
1083   name_typing = FALSE;
1084
1085   CloseDoor(DOOR_CLOSE_ALL);
1086
1087   OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
1088
1089   if (level_editor_test_game)
1090   {
1091     for(x=0; x<lev_fieldx; x++)
1092       for(y=0; y<lev_fieldy; y++)
1093         Feld[x][y] = Ur[x][y];
1094
1095     for(x=0; x<lev_fieldx; x++)
1096       for(y=0; y<lev_fieldy; y++)
1097         Ur[x][y] = FieldBackup[x][y];
1098
1099     level_editor_test_game = FALSE;
1100   }
1101   else
1102   {
1103     undo_buffer_position = -1;
1104     undo_buffer_steps = -1;
1105     CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
1106   }
1107
1108   /*
1109   DrawMiniLevel(level_xpos, level_ypos);
1110   FadeToFront();
1111   */
1112
1113   XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1114             DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY1,
1115             DXSIZE,DYSIZE,
1116             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1117   XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1118             DOOR_GFX_PAGEX6+ED_BUTTON_ELEM_XPOS,
1119             DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS,
1120             4*ED_BUTTON_ELEM_XSIZE,5*ED_BUTTON_ELEM_YSIZE,
1121             DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS,
1122             DOOR_GFX_PAGEY1+ED_BUTTON_EUP_Y2POS);
1123
1124   for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1125   {
1126     if (i < elements_in_list)
1127       graphic = el2gfx(editor_element[i + element_shift]);
1128     else
1129       graphic = GFX_LEERRAUM;
1130
1131     DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1132                        DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS+3 + 
1133                        (i%MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
1134                        DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS+3 +
1135                        (i/MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
1136                        graphic);
1137   }
1138
1139   DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1140                      DOOR_GFX_PAGEX1+ED_WIN_MB_LEFT_XPOS,
1141                      DOOR_GFX_PAGEY1+ED_WIN_MB_LEFT_YPOS,
1142                      el2gfx(new_element1));
1143   DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1144                      DOOR_GFX_PAGEX1+ED_WIN_MB_MIDDLE_XPOS,
1145                      DOOR_GFX_PAGEY1+ED_WIN_MB_MIDDLE_YPOS,
1146                      el2gfx(new_element2));
1147   DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1148                      DOOR_GFX_PAGEX1+ED_WIN_MB_RIGHT_XPOS,
1149                      DOOR_GFX_PAGEY1+ED_WIN_MB_RIGHT_YPOS,
1150                      el2gfx(new_element3));
1151   DrawTextExt(pix[PIX_DB_DOOR],gc,
1152               DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS,
1153               DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1154               int2str(level_nr,2),FS_SMALL,FC_SPECIAL1);
1155   XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1156             DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+3,
1157             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1158             7,FONT3_YSIZE,
1159             DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS,
1160             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1161   XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1162             DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+14,
1163             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1164             7,FONT3_YSIZE,
1165             DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS+9,
1166             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1167
1168   XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1169             DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1170             VXSIZE,VYSIZE,
1171             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1172
1173   /* draw bigger door */
1174   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1175             DOOR_GFX_PAGEX7, 0,
1176             108, 64,
1177             EX - 4, EY - 12);
1178
1179   /* draw new control window */
1180   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1181             DOOR_GFX_PAGEX8, 236,
1182             EXSIZE, EYSIZE,
1183             EX, EY);
1184
1185   redraw_mask |= REDRAW_ALL;
1186
1187   OpenDoor(DOOR_OPEN_1);
1188
1189   if (!level_editor_gadgets_created)
1190     CreateLevelEditorGadgets();
1191
1192   MapControlButtons();
1193
1194   /*
1195   MapMainDrawingArea();
1196   */
1197
1198   DrawDrawingWindow();
1199   FadeToFront();
1200
1201   /*
1202   OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
1203   */
1204 }
1205
1206 void DrawControlWindow()
1207 {
1208   int i,x,y;
1209
1210   ClearWindow();
1211   UnmapLevelEditorWindowGadgets();
1212
1213   /* Inhalt der Mampfer */
1214   DrawText(ED_COUNT_GADGET_XPOS+1,SY+6,
1215            "Contents of a smashed cruncher:",FS_SMALL,FC_YELLOW);
1216   for(i=0;i<4;i++) for(y=0;y<4;y++) for(x=0;x<4;x++)
1217   {
1218     DrawMiniElement(1+5*i+x,2+y,EL_ERDREICH);
1219     XFillRectangle(display,drawto,gc,
1220                    SX+(1+5*i)*MINI_TILEX+MINI_TILEX/2-1,
1221                    SY+(2)*MINI_TILEY+MINI_TILEY/2-1,
1222                    3*MINI_TILEX+2,3*MINI_TILEY+2);
1223   }
1224   XCopyArea(display,drawto,drawto,gc,
1225             SX+1*MINI_TILEX,SY+2*MINI_TILEY,
1226             4*5*MINI_TILEX,5*MINI_TILEY,
1227             SX+1*MINI_TILEX-MINI_TILEX/2,SY+2*MINI_TILEY-MINI_TILEY/2);
1228   for(i=0;i<4;i++)
1229   {
1230     for(y=0;y<3;y++) for(x=0;x<3;x++)
1231       DrawMiniElement(1+5*i+x,2+y,level.mampfer_inhalt[i][x][y]);
1232
1233     DrawText(SX+MINI_TILEX+(5*i+1)*MINI_TILEX+1,
1234              SY+2*MINI_TILEY+(4)*MINI_TILEY-4,
1235              int2str(i+1,1),FS_SMALL,FC_YELLOW);
1236   }
1237
1238   /* Inhalt der Amöbe */
1239   for(y=0;y<2;y++) for(x=0;x<2;x++)
1240   {
1241     DrawMiniElement(29+x,26+y,EL_ERDREICH);
1242     XFillRectangle(display,drawto,gc,
1243                    SX+29*MINI_TILEX+MINI_TILEX/2-1,
1244                    SY+26*MINI_TILEY+MINI_TILEY/2-1,
1245                    MINI_TILEX+2,MINI_TILEY+2);
1246   }
1247   XCopyArea(display,drawto,drawto,gc,
1248             SX+29*MINI_TILEX,SY+26*MINI_TILEY,
1249             3*MINI_TILEX,3*MINI_TILEY,
1250             SX+29*MINI_TILEX-MINI_TILEX/2,SY+26*MINI_TILEY-MINI_TILEY/2);
1251   DrawMiniElement(29,26,level.amoebe_inhalt);
1252
1253   for(i=0;i<11+3+2;i++)
1254   {
1255     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1256               DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1257               DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1258               DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1259               ED_COUNT_GADGET_XPOS,
1260               ED_COUNT_GADGET_YPOS+i*ED_COUNT_GADGET_YSIZE);
1261
1262     if (i<11)
1263       DrawText(ED_COUNT_VALUE_XPOS,
1264                ED_COUNT_VALUE_YPOS+i*ED_COUNT_GADGET_YSIZE,
1265                int2str(level.score[i],3),FS_SMALL,FC_YELLOW);
1266     else if (i==11)
1267       DrawText(ED_COUNT_VALUE_XPOS,
1268                ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1269                int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1270     else if (i==12)
1271       DrawText(ED_COUNT_VALUE_XPOS,
1272                ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1273                int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1274     else if (i==13)
1275       DrawText(ED_COUNT_VALUE_XPOS,
1276                ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1277                int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1278     else if (i==14)
1279       DrawText(ED_COUNT_VALUE_XPOS,
1280                ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1281                int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1282     else if (i==15)
1283       DrawText(ED_COUNT_VALUE_XPOS,
1284                ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1285                int2str(level.time,3),FS_SMALL,FC_YELLOW);
1286   }
1287
1288   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+0*ED_COUNT_TEXT_YSIZE,
1289            "Score for Emerald",FS_SMALL,FC_YELLOW);
1290   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+1*ED_COUNT_TEXT_YSIZE,
1291            "Score for Diamond",FS_SMALL,FC_YELLOW);
1292   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+2*ED_COUNT_TEXT_YSIZE,
1293            "Score for smashing a Bug",FS_SMALL,FC_YELLOW);
1294   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+3*ED_COUNT_TEXT_YSIZE,
1295            "Score for smashing a Spaceship",FS_SMALL,FC_YELLOW);
1296   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+4*ED_COUNT_TEXT_YSIZE,
1297            "Score for smashing a Cruncher",FS_SMALL,FC_YELLOW);
1298   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+5*ED_COUNT_TEXT_YSIZE,
1299            "Score for smashing an Alien",FS_SMALL,FC_YELLOW);
1300   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+6*ED_COUNT_TEXT_YSIZE,
1301            "Score for smashing a Pacman",FS_SMALL,FC_YELLOW);
1302   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+7*ED_COUNT_TEXT_YSIZE,
1303            "Score for cracking a nut",FS_SMALL,FC_YELLOW);
1304   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+8*ED_COUNT_TEXT_YSIZE,
1305            "Score for dynamite",FS_SMALL,FC_YELLOW);
1306   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+9*ED_COUNT_TEXT_YSIZE,
1307            "Score for key",FS_SMALL,FC_YELLOW);
1308   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+10*ED_COUNT_TEXT_YSIZE,
1309            "Score for each 10 seconds left",FS_SMALL,FC_YELLOW);
1310   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+11*ED_COUNT_TEXT_YSIZE,
1311            "Speed of the amoeba / Content",FS_SMALL,FC_YELLOW);
1312   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+12*ED_COUNT_TEXT_YSIZE,
1313            "Time for magic wall",FS_SMALL,FC_YELLOW);
1314   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+13*ED_COUNT_TEXT_YSIZE,
1315            "Time for wheel",FS_SMALL,FC_YELLOW);
1316   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+14*ED_COUNT_TEXT_YSIZE,
1317            "Emeralds needed in this level",FS_SMALL,FC_YELLOW);
1318   DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+15*ED_COUNT_TEXT_YSIZE,
1319            "Time available for this level",FS_SMALL,FC_YELLOW);
1320
1321   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1322             DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS,
1323             DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1324             ED_WIN_COUNT_XSIZE,ED_WIN_COUNT_YSIZE,
1325             ED_COUNT_GADGET_XPOS,
1326             ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1327   for(i=1;i<31;i++)
1328     XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1329               DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS+3+2*FONT2_XSIZE,
1330               DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1331               ED_WIN_COUNT_XSIZE-3-2*FONT2_XSIZE,ED_WIN_COUNT_YSIZE,
1332               ED_COUNT_GADGET_XPOS+3+i*FONT2_XSIZE,
1333               ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1334   DrawText(ED_COUNT_GADGET_XPOS+5,
1335            ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1336            level.name,FS_SMALL,FC_YELLOW);
1337   DrawText(ED_COUNT_GADGET_XPOS+(30+3)*FONT2_XSIZE-5,
1338            ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1339            "Title",FS_SMALL,FC_YELLOW);
1340
1341   DrawText(ED_SIZE_GADGET_XPOS,ED_SIZE_GADGET_YPOS-18,
1342            "Playfield size:",FS_SMALL,FC_YELLOW);
1343   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1344             DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1345             DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1346             DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1347             ED_SIZE_GADGET_XPOS,
1348             ED_SIZE_GADGET_YPOS+0*ED_COUNT_GADGET_YSIZE);
1349   XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1350             DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1351             DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1352             DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1353             ED_SIZE_GADGET_XPOS,
1354             ED_SIZE_GADGET_YPOS+1*ED_COUNT_GADGET_YSIZE);
1355   DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+0*ED_SIZE_TEXT_YSIZE,
1356            "Width",FS_SMALL,FC_YELLOW);
1357   DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+1*ED_SIZE_TEXT_YSIZE,
1358            "Height",FS_SMALL,FC_YELLOW);
1359   DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1360            int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1361   DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1362            int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1363 }
1364
1365 void AdjustLevelScrollPosition()
1366 {
1367   if (level_xpos < -1)
1368     level_xpos = -1;
1369   if (level_xpos > lev_fieldx - ED_FIELDX + 1)
1370     level_xpos = lev_fieldx - ED_FIELDX + 1;
1371   if (lev_fieldx < ED_FIELDX - 2)
1372     level_xpos = -1;
1373
1374   if (level_ypos < -1)
1375     level_ypos = -1;
1376   if (level_ypos > lev_fieldy - ED_FIELDY + 1)
1377     level_ypos = lev_fieldy - ED_FIELDY + 1;
1378   if (lev_fieldy < ED_FIELDY - 2)
1379     level_ypos = -1;
1380 }
1381
1382 static void PickDrawingElement(int button, int element)
1383 {
1384   if (button < 1 || button > 3)
1385     return;
1386
1387   if (button == 1)
1388   {
1389     new_element1 = element;
1390     DrawMiniGraphicExt(drawto, gc,
1391                        DX + ED_WIN_MB_LEFT_XPOS,
1392                        DY + ED_WIN_MB_LEFT_YPOS,
1393                        el2gfx(new_element1));
1394   }
1395   else if (button == 2)
1396   {
1397     new_element2 = element;
1398     DrawMiniGraphicExt(drawto, gc,
1399                        DX + ED_WIN_MB_MIDDLE_XPOS,
1400                        DY + ED_WIN_MB_MIDDLE_YPOS,
1401                        el2gfx(new_element2));
1402   }
1403   else
1404   {
1405     new_element3 = element;
1406     DrawMiniGraphicExt(drawto, gc,
1407                        DX + ED_WIN_MB_RIGHT_XPOS,
1408                        DY + ED_WIN_MB_RIGHT_YPOS,
1409                        el2gfx(new_element3));
1410   }
1411
1412   redraw_mask |= REDRAW_DOOR_1;
1413 }
1414
1415 void LevelEd(int mx, int my, int button)
1416 {
1417   static int last_button = 0;
1418   static int in_field_pressed = FALSE;
1419   static boolean use_floodfill = FALSE;
1420
1421
1422   /*
1423   int x = (mx-SX)/MINI_TILEX; 
1424   int y = (my-SY)/MINI_TILEY; 
1425   */
1426
1427   /*
1428   HandlePressedControlButtons();
1429   HandleDrawingFunctions(mx, my, button);
1430   */
1431
1432   if (use_floodfill)            /********** FLOOD FILL **********/
1433   {
1434
1435
1436 #if 0
1437
1438     if (button)
1439     {
1440       if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
1441       {
1442         int from_x, from_y;
1443         int fill_element;
1444
1445         if (x>lev_fieldx || y>lev_fieldy ||
1446             (x==0 && level_xpos<0) ||
1447             (x==ED_FIELDX-1 && level_xpos>lev_fieldx-ED_FIELDX) ||
1448             (y==0 && level_ypos<0) ||
1449             (y==ED_FIELDY-1 && level_ypos>lev_fieldy-ED_FIELDY))
1450           return;
1451
1452         from_x = x+level_xpos;
1453         from_y = y+level_ypos;
1454         fill_element = (button==1 ? new_element1 :
1455                         button==2 ? new_element2 :
1456                         button==3 ? new_element3 : 0);
1457
1458         FloodFill(from_x,from_y,fill_element);
1459         DrawMiniLevel(level_xpos,level_ypos);
1460       }
1461
1462       use_floodfill = FALSE;
1463       CloseDoor(DOOR_CLOSE_1);
1464       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
1465     }
1466     return;
1467
1468 #endif
1469
1470
1471
1472   }
1473   else                          /********** EDIT/CTRL-FENSTER **********/
1474   {
1475     static unsigned long choice_delay = 0;
1476     int choice = CheckElemButtons(mx,my,button);
1477     int elem_pos = choice-ED_BUTTON_ELEM;
1478
1479     if (((choice == ED_BUTTON_EUP && element_shift>0) ||
1480          (choice == ED_BUTTON_EDOWN &&
1481           element_shift<elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)) &&
1482         DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1483     {
1484       int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
1485       int i;
1486
1487 #if 0
1488       step = (button==1 ? MAX_ELEM_X : button==2 ? 5*MAX_ELEM_X :
1489               elements_in_list);
1490       element_shift += (choice==ED_BUTTON_EUP ? -step : step);
1491 #else
1492       step = step * MAX_ELEM_X * (choice == ED_BUTTON_EUP ? -1 : +1);
1493       element_shift += step;
1494 #endif
1495
1496       if (element_shift<0)
1497         element_shift = 0;
1498       if (element_shift>elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)
1499         element_shift = elements_in_list-MAX_ELEM_X*MAX_ELEM_Y;
1500       if (element_shift % MAX_ELEM_X)
1501         element_shift += MAX_ELEM_X-(element_shift % MAX_ELEM_X);
1502
1503       for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1504         DrawElemButton(i+2,ED_BUTTON_RELEASED);
1505     }
1506     else if (elem_pos>=0 && elem_pos<MAX_ELEM_X*MAX_ELEM_Y)
1507     {
1508       int new_element;
1509
1510       if (elem_pos+element_shift < elements_in_list)
1511         new_element = editor_element[elem_pos+element_shift];
1512       else
1513         new_element = EL_LEERRAUM;
1514
1515       PickDrawingElement(last_button, new_element);
1516
1517       if (!HAS_CONTENT(properties_element))
1518       {
1519         properties_element = new_element;
1520         if (edit_mode == ED_MODE_PROPERTIES)
1521           DrawPropertiesWindow();
1522       }
1523     }
1524   
1525     if (edit_mode == ED_MODE_DRAWING)   /********** EDIT-FENSTER **********/
1526     {
1527
1528
1529
1530 #if 0
1531
1532       switch(CheckEditButtons(mx,my,button))
1533       {
1534         case ED_BUTTON_CTRL:
1535           CloseDoor(DOOR_CLOSE_2);
1536           DrawControlWindow();
1537           XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1538                     DOOR_GFX_PAGEX4,DOOR_GFX_PAGEY1+80,
1539                     VXSIZE,VYSIZE,
1540                     DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1541           OpenDoor(DOOR_OPEN_2);
1542           edit_mode = ED_MODE_INFO;
1543           break;
1544         case ED_BUTTON_FILL:
1545           Request("Caution ! Flood fill mode ! Choose area !",REQ_OPEN);
1546           use_floodfill = TRUE;
1547           return;
1548           break;
1549         case ED_BUTTON_LEFT:
1550           if (level_xpos>=0)
1551           {
1552             if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1553               break;
1554             if (lev_fieldx<ED_FIELDX-2)
1555               break;
1556
1557             level_xpos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
1558             if (level_xpos<-1)
1559               level_xpos = -1;
1560             if (button==1)
1561               ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_RIGHT);
1562             else
1563               DrawMiniLevel(level_xpos,level_ypos);
1564           }
1565           break;
1566         case ED_BUTTON_RIGHT:
1567           if (level_xpos<=lev_fieldx-ED_FIELDX)
1568           {
1569             if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1570               break;
1571             if (lev_fieldx<ED_FIELDX-2)
1572               break;
1573
1574             level_xpos += (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
1575             if (level_xpos>lev_fieldx-ED_FIELDX+1)
1576               level_xpos = lev_fieldx-ED_FIELDX+1;
1577             if (button==1)
1578               ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_LEFT);
1579             else
1580               DrawMiniLevel(level_xpos,level_ypos);
1581           }
1582           break;
1583         case ED_BUTTON_UP:
1584           if (level_ypos>=0)
1585           {
1586             if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1587               break;
1588             if (lev_fieldy<ED_FIELDY-2)
1589               break;
1590
1591             level_ypos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
1592             if (level_ypos<-1)
1593               level_ypos = -1;
1594             if (button==1)
1595               ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_DOWN);
1596             else
1597               DrawMiniLevel(level_xpos,level_ypos);
1598           }
1599           break;
1600         case ED_BUTTON_DOWN:
1601           if (level_ypos<=lev_fieldy-ED_FIELDY)
1602           {
1603             if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1604               break;
1605             if (lev_fieldy<ED_FIELDY-2)
1606               break;
1607
1608             level_ypos += (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
1609             if (level_ypos>lev_fieldy-ED_FIELDY+1)
1610               level_ypos = lev_fieldy-ED_FIELDY+1;
1611             if (button==1)
1612               ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_UP);
1613             else
1614               DrawMiniLevel(level_xpos,level_ypos);
1615           }
1616           break;
1617         default:
1618           break;
1619       }
1620
1621 #endif
1622
1623
1624
1625 #if 0
1626
1627       if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
1628       {
1629         int new_element;
1630
1631         if (button && !motion_status)
1632           in_field_pressed = TRUE;
1633
1634         if (!button || !in_field_pressed || button<1 || button>3 ||
1635             (y==0 && level_ypos<0) ||
1636             (y==ED_FIELDY-1 && level_ypos>lev_fieldy-ED_FIELDY) ||
1637             (x==0 && level_xpos<0) ||
1638             (x==ED_FIELDX-1 && level_xpos>lev_fieldx-ED_FIELDX) ||
1639             x>lev_fieldx || y>lev_fieldy)
1640           return;
1641
1642         new_element = (button==1 ? new_element1 :
1643                        button==2 ? new_element2 :
1644                        button==3 ? new_element3 : 0);
1645
1646         if (new_element != Feld[x+level_xpos][y+level_ypos])
1647         {
1648           if (new_element==EL_SPIELFIGUR) /* Jeder nur EINE Figur bitte... */
1649           {
1650             int x,y;
1651
1652             for(x=0;x<lev_fieldx;x++) for(y=0;y<lev_fieldy;y++)
1653             {
1654               if (Feld[x][y]==EL_SPIELFIGUR || Feld[x][y]==EL_SPIELER1)
1655               {
1656                 Feld[x][y] = EL_LEERRAUM;
1657                 if (x-level_xpos>=0 && x-level_xpos<ED_FIELDX &&
1658                     y-level_ypos>=0 && y-level_ypos<ED_FIELDY)
1659                   DrawMiniElement(x-level_xpos,y-level_ypos,EL_LEERRAUM);
1660               }
1661             }
1662           }
1663
1664           Feld[x+level_xpos][y+level_ypos] = new_element;
1665           DrawMiniElement(x,y,new_element);
1666         }
1667       }
1668       else if (!motion_status)  /* Mauszeiger nicht im Level-Feld */
1669         in_field_pressed = FALSE;
1670
1671 #endif
1672
1673
1674
1675     }
1676     else if (edit_mode == ED_MODE_INFO)/********** KONTROLL-FENSTER **********/
1677     {
1678       int choice = CheckCountButtons(mx,my,button);
1679       int step = (button==1 ? 1 : button==2 ? 5 : button==3 ? 10 : 0);
1680
1681       if (choice >= 0 && choice < 36 &&
1682           DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1683       {
1684         if (!(choice % 2))
1685           step = -step;
1686
1687         choice /= 2;
1688
1689         if (choice<11)
1690         {
1691           level.score[choice] += step;
1692           if (level.score[choice]<0)
1693             level.score[choice] = 0;
1694           else if (level.score[choice]>255)
1695             level.score[choice] = 255;
1696         }
1697         else if (choice==11)
1698         {
1699           level.tempo_amoebe += step;
1700           if (level.tempo_amoebe<0)
1701             level.tempo_amoebe = 0;
1702           else if (level.tempo_amoebe>255)
1703             level.tempo_amoebe = 255;
1704         }
1705         else if (choice==12)
1706         {
1707           level.dauer_sieb += step;
1708           if (level.dauer_sieb<0)
1709             level.dauer_sieb = 0;
1710           else if (level.dauer_sieb>255)
1711             level.dauer_sieb = 255;
1712         }
1713         else if (choice==13)
1714         {
1715           level.dauer_ablenk += step;
1716           if (level.dauer_ablenk<0)
1717             level.dauer_ablenk = 0;
1718           else if (level.dauer_ablenk>255)
1719             level.dauer_ablenk = 255;
1720         }
1721         else if (choice==14)
1722         {
1723           level.edelsteine += step;
1724           if (level.edelsteine<0)
1725             level.edelsteine = 0;
1726           else if (level.edelsteine>999)
1727             level.edelsteine = 999;
1728         }
1729         else if (choice==15)
1730         {
1731           level.time += step;
1732           if (level.time<0)
1733             level.time = 0;
1734           else if (level.time>999)
1735             level.time = 999;
1736         }
1737         else if (choice==16)
1738         {
1739           lev_fieldx += step;
1740           if (lev_fieldx<MIN_LEV_FIELDX)
1741             lev_fieldx = MIN_LEV_FIELDX;
1742           else if (lev_fieldx>MAX_LEV_FIELDX)
1743             lev_fieldx = MAX_LEV_FIELDX;
1744           level.fieldx = lev_fieldx;
1745         }
1746         else if (choice==17)
1747         {
1748           lev_fieldy += step;
1749           if (lev_fieldy<MIN_LEV_FIELDY)
1750             lev_fieldy = MIN_LEV_FIELDY;
1751           else if (lev_fieldy>MAX_LEV_FIELDY)
1752             lev_fieldy = MAX_LEV_FIELDY;
1753           level.fieldy = lev_fieldy;
1754         }
1755
1756         if (choice<11)
1757           DrawText(ED_COUNT_VALUE_XPOS,
1758                    ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
1759                    int2str(level.score[choice],3),FS_SMALL,FC_YELLOW);
1760         else if (choice==11)
1761           DrawText(ED_COUNT_VALUE_XPOS,
1762                    ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1763                    int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1764         else if (choice==12)
1765           DrawText(ED_COUNT_VALUE_XPOS,
1766                    ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1767                    int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1768         else if (choice==13)
1769           DrawText(ED_COUNT_VALUE_XPOS,
1770                    ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1771                    int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1772         else if (choice==14)
1773           DrawText(ED_COUNT_VALUE_XPOS,
1774                    ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1775                    int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1776         else if (choice==15)
1777           DrawText(ED_COUNT_VALUE_XPOS,
1778                    ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1779                    int2str(level.time,3),FS_SMALL,FC_YELLOW);
1780         else if (choice==16)
1781           DrawText(ED_SIZE_VALUE_XPOS,
1782                    ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1783                    int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1784         else if (choice==17)
1785           DrawText(ED_SIZE_VALUE_XPOS,
1786                    ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1787                    int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1788
1789         redraw_mask &= ~REDRAW_FIELD;
1790         if (choice<16)
1791           XCopyArea(display,drawto,window,gc,
1792                     ED_COUNT_VALUE_XPOS,
1793                     ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
1794                     3*FONT2_XSIZE,FONT2_YSIZE,
1795                     ED_COUNT_VALUE_XPOS,
1796                     ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE);
1797         else
1798           XCopyArea(display,drawto,window,gc,
1799                     ED_SIZE_VALUE_XPOS,
1800                     ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE,
1801                     3*FONT2_XSIZE,FONT2_YSIZE,
1802                     ED_SIZE_VALUE_XPOS,
1803                     ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE);
1804         XFlush(display);
1805       }
1806
1807
1808
1809 #if 0
1810
1811       switch(CheckCtrlButtons(mx,my,button))
1812       {
1813         case ED_BUTTON_EDIT:
1814           CloseDoor(DOOR_CLOSE_2);
1815           AdjustLevelScrollPosition();
1816           DrawMiniLevel(level_xpos,level_ypos);
1817           XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1818                     DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1819                     VXSIZE,VYSIZE,
1820                     DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1821           OpenDoor(DOOR_OPEN_2);
1822           edit_mode = ED_MODE_DRAWING;
1823           break;
1824         case ED_BUTTON_CLEAR:
1825           if (Request("Are you sure to clear this level ?",REQ_ASK))
1826           {
1827             for(x=0;x<MAX_LEV_FIELDX;x++) 
1828               for(y=0;y<MAX_LEV_FIELDY;y++) 
1829                 Feld[x][y] = EL_ERDREICH;
1830             DrawMiniLevel(level_xpos,level_ypos);
1831           }
1832           break;
1833         case ED_BUTTON_UNDO:
1834           if (leveldir[leveldir_nr].readonly ||
1835               Request("Exit without saving ?",REQ_ASK | REQ_STAY_OPEN))
1836           {
1837             CloseDoor(DOOR_CLOSE_ALL);
1838             game_status=MAINMENU;
1839             DrawMainMenu();
1840           }
1841           else
1842           {
1843             CloseDoor(DOOR_CLOSE_1);
1844             OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
1845           }
1846           break;
1847         case ED_BUTTON_EXIT:
1848           {
1849             int figur_vorhanden = FALSE;
1850
1851             if (leveldir[leveldir_nr].readonly)
1852             {
1853               Request("This level is read only !",REQ_CONFIRM);
1854               break;
1855             }
1856
1857             for(y=0;y<lev_fieldy;y++) 
1858               for(x=0;x<lev_fieldx;x++)
1859                 if (Feld[x][y] == EL_SPIELFIGUR ||
1860                     Feld[x][y] == EL_SPIELER1 ||
1861                     Feld[x][y] == EL_SP_MURPHY) 
1862                   figur_vorhanden = TRUE;
1863
1864             if (!figur_vorhanden)
1865               Request("No Level without Gregor Mc Duffin please !",
1866                          REQ_CONFIRM);
1867             else
1868             {
1869               if (Request("Save this level and kill the old ?",
1870                              REQ_ASK | REQ_STAY_OPEN))
1871               {
1872                 for(x=0;x<lev_fieldx;x++)
1873                   for(y=0;y<lev_fieldy;y++) 
1874                     Ur[x][y]=Feld[x][y];
1875                 SaveLevel(level_nr);
1876               }
1877               CloseDoor(DOOR_CLOSE_ALL);
1878               game_status=MAINMENU;
1879               DrawMainMenu();
1880             }
1881           }
1882           break;
1883         default:
1884           break;
1885       }
1886
1887 #endif
1888
1889
1890
1891       if (mx>=ED_COUNT_GADGET_XPOS &&
1892           mx<ED_COUNT_GADGET_XPOS+31*FONT2_XSIZE+10 &&
1893           my>=ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE &&
1894           my<ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE+ED_WIN_COUNT_YSIZE)
1895       {
1896         if (!name_typing)
1897         {
1898           name_typing = TRUE;
1899           DrawText(ED_COUNT_GADGET_XPOS+5,
1900                    ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1901                    level.name,FS_SMALL,FC_GREEN);
1902           DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
1903                    ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1904                    "<",FS_SMALL,FC_RED);
1905         }
1906       }
1907       else
1908       {
1909         if (name_typing)
1910         {
1911           name_typing = FALSE;
1912           DrawText(ED_COUNT_GADGET_XPOS+5,
1913                    ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1914                    level.name,FS_SMALL,FC_YELLOW);
1915           DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
1916                    ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1917                    " ",FS_SMALL,FC_RED);
1918         }
1919       }
1920
1921       if (mx>=SX+29*MINI_TILEX && mx<SX+30*MINI_TILEX &&
1922           my>=SY+26*MINI_TILEY && my<SY+27*MINI_TILEY)
1923       {
1924         int new_element;
1925
1926         if (!button || button<1 || button>3)
1927           return;
1928
1929         new_element = (button==1 ? new_element1 :
1930                        button==2 ? new_element2 :
1931                        button==3 ? new_element3 : 0);
1932
1933         if (new_element != level.amoebe_inhalt)
1934         {
1935           level.amoebe_inhalt = new_element;
1936           DrawMiniElement(29,26,new_element);
1937         }
1938       }
1939
1940       if (mx>=SX+1*MINI_TILEX && mx<SX+(1+4*5)*MINI_TILEX &&
1941           my>=SY+2*MINI_TILEY && my<SY+(2+3)*MINI_TILEY)
1942       {
1943         int x = (mx-SX-1*MINI_TILEX)/MINI_TILEX;
1944         int y = (my-SY-2*MINI_TILEY)/MINI_TILEY;
1945         int i = x/5;
1946         int new_element;
1947
1948         x = x-i*5;
1949         if (i>=0 && i<43 && x>=0 && x<3 && y>=0 && y<3)
1950         {
1951           if (button && !motion_status)
1952             in_field_pressed = TRUE;
1953
1954           if (!button || !in_field_pressed || button<1 || button>3)
1955             return;
1956
1957           new_element = (button==1 ? new_element1 :
1958                          button==2 ? new_element2 :
1959                          button==3 ? new_element3 : 0);
1960
1961           if (new_element != level.mampfer_inhalt[i][x][y])
1962           {
1963             level.mampfer_inhalt[i][x][y] = new_element;
1964             DrawMiniElement(1+5*i+x,2+y,new_element);
1965           }
1966         }
1967         else if (!motion_status)/* Mauszeiger nicht im Cruncher-Feld */
1968           in_field_pressed = FALSE;
1969       }
1970       else if (!motion_status)  /* Mauszeiger nicht im Cruncher-Feld */
1971         in_field_pressed = FALSE;
1972     }
1973   }
1974
1975   last_button = button;
1976
1977   BackToFront();
1978 }
1979
1980 void LevelNameTyping(KeySym key)
1981 {
1982   unsigned char ascii = 0;
1983   int len = strlen(level.name);
1984
1985   if (!name_typing)
1986     return;
1987
1988   if (key>=XK_A && key<=XK_Z)
1989     ascii = 'A'+(char)(key-XK_A);
1990   else if (key>=XK_a && key<=XK_z)
1991     ascii = 'a'+(char)(key-XK_a);
1992   else if (key>=XK_0 && key<=XK_9)
1993     ascii = '0'+(char)(key-XK_0);
1994 #ifdef XK_LATIN1
1995   else if (key>=XK_space && key<=XK_at)
1996     ascii = ' '+(char)(key-XK_space);
1997   else if (key==XK_Adiaeresis)
1998     ascii = 'Ä';
1999   else if (key==XK_Odiaeresis)
2000     ascii = 'Ö';
2001   else if (key==XK_Udiaeresis)
2002     ascii = 'Ü';
2003   else if (key==XK_adiaeresis)
2004     ascii = 'ä';
2005   else if (key==XK_odiaeresis)
2006     ascii = 'ö';
2007   else if (key==XK_udiaeresis)
2008     ascii = 'ü';
2009   else if (key==XK_underscore)
2010     ascii = '_';
2011 #endif
2012
2013   if (ascii && len<MAX_LEVNAMLEN-2)
2014   {
2015     level.name[len] = ascii;
2016     level.name[len+1] = 0;
2017     len++;
2018
2019     DrawTextExt(drawto,gc,
2020                 ED_COUNT_GADGET_XPOS+5,
2021                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2022                 level.name,FS_SMALL,FC_GREEN);
2023     DrawTextExt(window,gc,
2024                 ED_COUNT_GADGET_XPOS+5,
2025                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2026                 level.name,FS_SMALL,FC_GREEN);
2027     DrawTextExt(drawto,gc,
2028                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2029                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2030                 "<",FS_SMALL,FC_RED);
2031     DrawTextExt(window,gc,
2032                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2033                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2034                 "<",FS_SMALL,FC_RED);
2035   }
2036   else if ((key==XK_Delete || key==XK_BackSpace) && len>0)
2037   {
2038     level.name[len-1] = 0;
2039     len--;
2040
2041     DrawTextExt(drawto,gc,
2042                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2043                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2044                 "< ",FS_SMALL,FC_GREEN);
2045     DrawTextExt(window,gc,
2046                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2047                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2048                 "< ",FS_SMALL,FC_GREEN);
2049   }
2050   else if (key==XK_Return)
2051   {
2052     DrawTextExt(drawto,gc,
2053                 ED_COUNT_GADGET_XPOS+5,
2054                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2055                 level.name,FS_SMALL,FC_YELLOW);
2056     DrawTextExt(window,gc,
2057                 ED_COUNT_GADGET_XPOS+5,
2058                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2059                 level.name,FS_SMALL,FC_YELLOW);
2060     DrawTextExt(drawto,gc,
2061                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2062                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2063                 " ",FS_SMALL,FC_YELLOW);
2064     DrawTextExt(window,gc,
2065                 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2066                 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2067                 " ",FS_SMALL,FC_YELLOW);
2068
2069     name_typing = FALSE;
2070   }
2071 }
2072
2073 static void DrawCounterValueField(int counter_id, int value)
2074 {
2075   int x = SX + counterbutton_info[counter_id].x + ED_WIN_COUNT_XPOS;
2076   int y = SY + counterbutton_info[counter_id].y;
2077
2078   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2079             DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS,
2080             DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS,
2081             ED_WIN_COUNT_XSIZE, ED_WIN_COUNT_YSIZE,
2082             x, y);
2083
2084   DrawText(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2085            int2str(value, 3), FS_SMALL, FC_YELLOW);
2086 }
2087
2088 static void DrawDrawingWindow()
2089 {
2090   ClearWindow();
2091   UnmapLevelEditorWindowGadgets();
2092   MapMainDrawingArea();
2093   AdjustLevelScrollPosition();
2094   DrawMiniLevel(level_xpos, level_ypos);
2095 }
2096
2097 static void DrawElementContentAreas()
2098 {
2099   int *num_areas = &MampferMax;
2100   int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX;
2101   int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY;
2102   int area_sx = SX + ED_AREA_ELEMCONT_XPOS;
2103   int area_sy = SY + ED_AREA_ELEMCONT_YPOS;
2104   int i, x, y;
2105
2106   for (i=0; i<MAX_ELEMCONT; i++)
2107     for (y=0; y<3; y++)
2108       for (x=0; x<3; x++)
2109         ElementContent[i][x][y] = level.mampfer_inhalt[i][x][y];
2110
2111   for (i=0; i<MAX_ELEMCONT; i++)
2112     UnmapDrawingArea(ED_CTRL_ID_ELEMCONT_0 + i);
2113
2114   /* display counter to choose number of element content areas */
2115   gadget_areas_value = num_areas;
2116   DrawCounterValueField(ED_COUNTER_ELEMCONT, *gadget_areas_value);
2117   x = counterbutton_info[ED_COUNTER_ELEMCONT].x + DXSIZE;
2118   y = counterbutton_info[ED_COUNTER_ELEMCONT].y;
2119   DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2120             FC_YELLOW, "number of content areas");
2121   MapCounterButtons(ED_COUNTER_ELEMCONT);
2122
2123   /* delete content areas in case of reducing number of them */
2124   XFillRectangle(display, backbuffer, gc,
2125                  SX, area_sy - MINI_TILEX,
2126                  SXSIZE, 12 * MINI_TILEY);
2127
2128   /* draw some decorative border for the objects */
2129   for (i=0; i<*num_areas; i++)
2130   {
2131     for (y=0; y<4; y++)
2132       for (x=0; x<4; x++)
2133         DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2134                         EL_ERDREICH);
2135
2136     XFillRectangle(display, drawto, gc,
2137                    area_sx + 5 * (i % 4) * MINI_TILEX + MINI_TILEX/2 - 1,
2138                    area_sy + 6 * (i / 4) * MINI_TILEY + MINI_TILEY/2 - 1,
2139                    3 * MINI_TILEX + 2, 3 * MINI_TILEY + 2);
2140   }
2141
2142   /* copy border to the right location */
2143   XCopyArea(display, drawto, drawto, gc,
2144             area_sx, area_sy, (5 * 4 + 1) * MINI_TILEX, 12 * MINI_TILEY,
2145             area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2146
2147   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
2148            "Content", FS_SMALL, FC_YELLOW);
2149   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
2150            "when", FS_SMALL, FC_YELLOW);
2151   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
2152            "smashed", FS_SMALL, FC_YELLOW);
2153
2154   for (i=0; i<*num_areas; i++)
2155   {
2156     for (y=0; y<3; y++)
2157       for (x=0; x<3; x++)
2158         DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2159                         ElementContent[i][x][y]);
2160
2161     DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
2162               area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
2163               FC_YELLOW, "%d", i + 1);
2164   }
2165
2166   for (i=0; i<*num_areas; i++)
2167     MapDrawingArea(ED_CTRL_ID_ELEMCONT_0 + i);
2168 }
2169
2170 static void DrawAmoebaContentArea()
2171 {
2172   int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX;
2173   int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY;
2174   int area_sx = SX + ED_AREA_ELEMCONT_XPOS;
2175   int area_sy = SY + ED_AREA_ELEMCONT_YPOS;
2176   int x, y;
2177
2178   ElementContent[0][0][0] = level.amoebe_inhalt;
2179
2180   /* draw decorative border for the object */
2181   for (y=0; y<2; y++)
2182     for (x=0; x<2; x++)
2183       DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
2184
2185   XFillRectangle(display, drawto, gc,
2186                  area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
2187                  MINI_TILEX + 2, MINI_TILEY + 2);
2188
2189   /* copy border to the right location */
2190   XCopyArea(display, drawto, drawto, gc,
2191             area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
2192             area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2193
2194   DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba",
2195            FS_SMALL, FC_YELLOW);
2196
2197   DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
2198
2199   MapDrawingArea(ED_CTRL_ID_AMOEBA_CONTENT);
2200 }
2201
2202 #define TEXT_COLLECTING         "Score for collecting"
2203 #define TEXT_SMASHING           "Score for smashing"
2204 #define TEXT_CRACKING           "Score for cracking"
2205 #define TEXT_SPEED              "Speed of amoeba growth"
2206 #define TEXT_DURATION           "Duration when activated"
2207
2208 static void DrawPropertiesWindow()
2209 {
2210   int i, x, y;
2211   int num_elements_in_level;
2212   static struct
2213   {
2214     int element;
2215     int *counter_value;
2216     char *text;
2217   } elements_with_counter[] =
2218   {
2219     { EL_EDELSTEIN,     &level.score[0],        TEXT_COLLECTING },
2220     { EL_EDELSTEIN_BD,  &level.score[0],        TEXT_COLLECTING },
2221     { EL_EDELSTEIN_GELB,&level.score[0],        TEXT_COLLECTING },
2222     { EL_EDELSTEIN_ROT, &level.score[0],        TEXT_COLLECTING },
2223     { EL_EDELSTEIN_LILA,&level.score[0],        TEXT_COLLECTING },
2224     { EL_DIAMANT,       &level.score[1],        TEXT_COLLECTING },
2225     { EL_KAEFER_R,      &level.score[2],        TEXT_SMASHING },
2226     { EL_KAEFER_O,      &level.score[2],        TEXT_SMASHING },
2227     { EL_KAEFER_L,      &level.score[2],        TEXT_SMASHING },
2228     { EL_KAEFER_U,      &level.score[2],        TEXT_SMASHING },
2229     { EL_BUTTERFLY_R,   &level.score[2],        TEXT_SMASHING },
2230     { EL_BUTTERFLY_O,   &level.score[2],        TEXT_SMASHING },
2231     { EL_BUTTERFLY_L,   &level.score[2],        TEXT_SMASHING },
2232     { EL_BUTTERFLY_U,   &level.score[2],        TEXT_SMASHING },
2233     { EL_FLIEGER_R,     &level.score[3],        TEXT_SMASHING },
2234     { EL_FLIEGER_O,     &level.score[3],        TEXT_SMASHING },
2235     { EL_FLIEGER_L,     &level.score[3],        TEXT_SMASHING },
2236     { EL_FLIEGER_U,     &level.score[3],        TEXT_SMASHING },
2237     { EL_FIREFLY_R,     &level.score[3],        TEXT_SMASHING },
2238     { EL_FIREFLY_O,     &level.score[3],        TEXT_SMASHING },
2239     { EL_FIREFLY_L,     &level.score[3],        TEXT_SMASHING },
2240     { EL_FIREFLY_U,     &level.score[3],        TEXT_SMASHING },
2241     { EL_MAMPFER,       &level.score[4],        TEXT_SMASHING },
2242     { EL_MAMPFER2,      &level.score[4],        TEXT_SMASHING },
2243     { EL_ROBOT,         &level.score[5],        TEXT_SMASHING },
2244     { EL_PACMAN_R,      &level.score[6],        TEXT_SMASHING },
2245     { EL_PACMAN_O,      &level.score[6],        TEXT_SMASHING },
2246     { EL_PACMAN_L,      &level.score[6],        TEXT_SMASHING },
2247     { EL_PACMAN_U,      &level.score[6],        TEXT_SMASHING },
2248     { EL_KOKOSNUSS,     &level.score[7],        TEXT_CRACKING },
2249     { EL_DYNAMIT_AUS,   &level.score[8],        TEXT_COLLECTING },
2250     { EL_SCHLUESSEL1,   &level.score[9],        TEXT_COLLECTING },
2251     { EL_SCHLUESSEL2,   &level.score[9],        TEXT_COLLECTING },
2252     { EL_SCHLUESSEL3,   &level.score[9],        TEXT_COLLECTING },
2253     { EL_SCHLUESSEL4,   &level.score[9],        TEXT_COLLECTING },
2254     { EL_AMOEBE_NASS,   &level.tempo_amoebe,    TEXT_SPEED },
2255     { EL_AMOEBE_NORM,   &level.tempo_amoebe,    TEXT_SPEED },
2256     { EL_AMOEBE_VOLL,   &level.tempo_amoebe,    TEXT_SPEED },
2257     { EL_AMOEBE_BD,     &level.tempo_amoebe,    TEXT_SPEED },
2258     { EL_SIEB_INAKTIV,  &level.dauer_sieb,      TEXT_DURATION },
2259     { EL_ABLENK_AUS,    &level.dauer_ablenk,    TEXT_DURATION },
2260     { -1, NULL, NULL }
2261   };
2262
2263   ClearWindow();
2264   UnmapLevelEditorWindowGadgets();
2265
2266   /* draw some decorative border for the object */
2267   for (y=0; y<3; y++)
2268     for (x=0; x<3; x++)
2269       DrawMiniElement(2 + x , 2 + y, EL_ERDREICH);
2270
2271   XFillRectangle(display, drawto, gc,
2272                  SX + TILEX + MINI_TILEX/2 - 1,
2273                  SY + TILEY + MINI_TILEY/2 - 1,
2274                  TILEX + 2, TILEY + 2);
2275
2276   /* copy border to the right location */
2277   XCopyArea(display, drawto, drawto, gc,
2278             SX + TILEX, SY + TILEY,
2279             2 * TILEX, 2 * TILEY,
2280             SX + TILEX - MINI_TILEX/2, SY + TILEY - MINI_TILEY/2);
2281
2282   DrawGraphic(1, 1, el2gfx(properties_element));
2283   DrawText(SX + 3*TILEX, SY + 5*TILEY/4, "Element Properties",
2284            FS_SMALL, FC_YELLOW);
2285
2286   num_elements_in_level = 0;
2287   for (y=0; y<lev_fieldy; y++) 
2288     for (x=0; x<lev_fieldx; x++)
2289       if (Feld[x][y] == properties_element)
2290         num_elements_in_level++;
2291
2292   DrawTextF(ED_PROPERTIES_XPOS, 5*TILEY, FC_YELLOW, "%d x contained in level",
2293             num_elements_in_level);
2294
2295   /* check if there are elements where a score can be chosen for */
2296   for (i=0; elements_with_counter[i].element != -1; i++)
2297   {
2298     if (elements_with_counter[i].element == properties_element)
2299     {
2300       int x = counterbutton_info[ED_COUNTER_SCORE].x + DXSIZE;
2301       int y = counterbutton_info[ED_COUNTER_SCORE].y;
2302
2303       gadget_score_value = elements_with_counter[i].counter_value;
2304       DrawCounterValueField(ED_COUNTER_SCORE, *gadget_score_value);
2305       DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2306                 FC_YELLOW, elements_with_counter[i].text);
2307       MapCounterButtons(ED_COUNTER_SCORE);
2308       break;
2309     }
2310   }
2311
2312   if (HAS_CONTENT(properties_element))
2313   {
2314     if (IS_AMOEBOID(properties_element))
2315       DrawAmoebaContentArea();
2316     else
2317       DrawElementContentAreas();
2318   }
2319
2320   /* TEST ONLY: level name text input gadget */
2321   MapTextInputGadget(ED_CTRL_ID_LEVEL_NAME);
2322 }
2323
2324 static void swap_numbers(int *i1, int *i2)
2325 {
2326   int help = *i1;
2327
2328   *i1 = *i2;
2329   *i2 = help;
2330 }
2331
2332 static void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
2333 {
2334   int help_x = *x1;
2335   int help_y = *y1;
2336
2337   *x1 = *x2;
2338   *x2 = help_x;
2339
2340   *y1 = *y2;
2341   *y2 = help_y;
2342 }
2343
2344 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
2345 {
2346   int lx = sx + level_xpos;
2347   int ly = sy + level_ypos;
2348
2349   DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element));
2350
2351   if (change_level)
2352     Feld[lx][ly] = element;
2353 }
2354
2355 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
2356                      int element, boolean change_level)
2357 {
2358   if (from_y == to_y)                   /* horizontal line */
2359   {
2360     int x;
2361     int y = from_y;
2362
2363     if (from_x > to_x)
2364       swap_numbers(&from_x, &to_x);
2365
2366     for (x=from_x; x<=to_x; x++)
2367       DrawLineElement(x, y, element, change_level);
2368   }
2369   else if (from_x == to_x)              /* vertical line */
2370   {
2371     int x = from_x;
2372     int y;
2373
2374     if (from_y > to_y)
2375       swap_numbers(&from_y, &to_y);
2376
2377     for (y=from_y; y<=to_y; y++)
2378       DrawLineElement(x, y, element, change_level);
2379   }
2380   else                                  /* diagonal line */
2381   {
2382     int len_x = ABS(to_x - from_x);
2383     int len_y = ABS(to_y - from_y);
2384     int x, y;
2385
2386     if (len_y < len_x)                  /* a < 1 */
2387     {
2388       float a = (float)len_y / (float)len_x;
2389
2390       if (from_x > to_x)
2391         swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2392
2393       for (x=0; x<=len_x; x++)
2394       {
2395         int y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1);
2396
2397         DrawLineElement(from_x + x, from_y + y, element, change_level);
2398       }
2399     }
2400     else                                /* a >= 1 */
2401     {
2402       float a = (float)len_x / (float)len_y;
2403
2404       if (from_y > to_y)
2405         swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2406
2407       for (y=0; y<=len_y; y++)
2408       {
2409         int x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1);
2410
2411         DrawLineElement(from_x + x, from_y + y, element, change_level);
2412       }
2413     }
2414   }
2415 }
2416
2417 static void DrawRectangle(int from_x, int from_y, int to_x, int to_y,
2418                           int element, boolean change_level)
2419 {
2420   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
2421   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
2422   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
2423   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
2424 }
2425
2426 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
2427                           int element, boolean change_level)
2428 {
2429   int y;
2430
2431   if (from_y > to_y)
2432     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2433
2434   for (y=from_y; y<=to_y; y++)
2435     DrawLine(from_x, y, to_x, y, element, change_level);
2436 }
2437
2438 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
2439 {
2440   int from_sx, from_sy;
2441   int to_sx, to_sy;
2442
2443   if (from_x > to_x)
2444     swap_numbers(&from_x, &to_x);
2445
2446   if (from_y > to_y)
2447     swap_numbers(&from_y, &to_y);
2448
2449   from_sx = SX + from_x * MINI_TILEX;
2450   from_sy = SY + from_y * MINI_TILEY;
2451   to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
2452   to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
2453
2454   XSetForeground(display, gc, WhitePixel(display, screen));
2455
2456   XDrawLine(display, drawto, gc, from_sx, from_sy, to_sx, from_sy);
2457   XDrawLine(display, drawto, gc, to_sx, from_sy, to_sx, to_sy);
2458   XDrawLine(display, drawto, gc, to_sx, to_sy, from_sx, to_sy);
2459   XDrawLine(display, drawto, gc, from_sx, to_sy, from_sx, from_sy);
2460
2461   XSetForeground(display, gc, BlackPixel(display, screen));
2462
2463   if (from_x == to_x && from_y == to_y)
2464     MarkTileDirty(from_x/2, from_y/2);
2465   else
2466     redraw_mask |= REDRAW_FIELD;
2467 }
2468
2469 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
2470                        int element, boolean change_level)
2471 {
2472   if (element == -1 || change_level)
2473     DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE);
2474   else
2475     DrawAreaBorder(from_x, from_y, to_x, to_y);
2476 }
2477
2478 /* values for CopyBrushExt() */
2479 #define CB_AREA_TO_BRUSH        0
2480 #define CB_BRUSH_TO_LEVEL       1
2481
2482 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, int mode)
2483 {
2484   static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
2485   static brush_from_x, brush_from_y;
2486   static brush_to_x, brush_to_y;
2487   int x, y;
2488
2489   if (from_x > to_x)
2490     swap_numbers(&from_x, &to_x);
2491
2492   if (from_y > to_y)
2493     swap_numbers(&from_y, &to_y);
2494
2495   if (mode == CB_AREA_TO_BRUSH)
2496   {
2497     for (y=from_y; y<=to_y; y++)
2498       for (x=from_x; x<=to_x; x++)
2499         brush_buffer[x][y] = Feld[x][y];
2500
2501     brush_from_x = from_x;
2502     brush_from_y = from_y;
2503     brush_to_x = to_x;
2504     brush_to_y = to_y;
2505   }
2506   else
2507   {
2508     for (y=brush_from_y; y<=brush_to_y; y++)
2509       for (x=brush_from_x; x<=brush_to_x; x++)
2510         Feld[x][y] = brush_buffer[x][y];
2511     CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2512   }
2513 }
2514
2515 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y)
2516 {
2517   CopyBrushExt(from_x, from_y, to_x, to_y, CB_AREA_TO_BRUSH);
2518 }
2519
2520 #if 0
2521 static void CopyBrushToLevel()
2522 {
2523   CopyBrushExt(0, 0, 0, 0, CB_BRUSH_TO_LEVEL);
2524 }
2525 #endif
2526
2527 static void FloodFill(int from_x, int from_y, int fill_element)
2528 {
2529   int i,x,y;
2530   int old_element;
2531   static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
2532   static int safety = 0;
2533
2534   /* check if starting field still has the desired content */
2535   if (Feld[from_x][from_y] == fill_element)
2536     return;
2537
2538   safety++;
2539
2540   if (safety > lev_fieldx*lev_fieldy)
2541     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
2542
2543   old_element = Feld[from_x][from_y];
2544   Feld[from_x][from_y] = fill_element;
2545
2546   for(i=0;i<4;i++)
2547   {
2548     x = from_x + check[i][0];
2549     y = from_y + check[i][1];
2550
2551     if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element)
2552       FloodFill(x, y, fill_element);
2553   }
2554
2555   safety--;
2556 }
2557
2558 /* values for DrawLevelText() modes */
2559 #define TEXT_INIT       0
2560 #define TEXT_SETCURSOR  1
2561 #define TEXT_WRITECHAR  2
2562 #define TEXT_BACKSPACE  3
2563 #define TEXT_NEWLINE    4
2564 #define TEXT_END        5
2565
2566 static void DrawLevelText(int sx, int sy, char letter, int mode)
2567 {
2568   static short delete_buffer[MAX_LEV_FIELDX];
2569   static int start_sx, start_sy;
2570   static int last_sx, last_sy;
2571   static boolean typing = FALSE;
2572   int letter_element = EL_CHAR_ASCII0 + letter;
2573   int lx, ly;
2574
2575   if (mode != TEXT_INIT)
2576   {
2577     if (!typing)
2578       return;
2579
2580     if (mode != TEXT_SETCURSOR)
2581     {
2582       sx = last_sx;
2583       sy = last_sy;
2584     }
2585
2586     lx = last_sx + level_xpos;
2587     ly = last_sy + level_ypos;
2588   }
2589
2590   switch (mode)
2591   {
2592     case TEXT_INIT:
2593       if (typing)
2594         DrawLevelText(0, 0, 0, TEXT_END);
2595
2596       typing = TRUE;
2597       start_sx = last_sx = sx;
2598       start_sy = last_sy = sy;
2599       DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
2600       break;
2601
2602     case TEXT_SETCURSOR:
2603       DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
2604       DrawAreaBorder(sx, sy, sx, sy);
2605       last_sx = sx;
2606       last_sy = sy;
2607       break;
2608
2609     case TEXT_WRITECHAR:
2610       if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
2611       {
2612         delete_buffer[sx - start_sx] = Feld[lx][ly];
2613         Feld[lx][ly] = letter_element;
2614
2615         if (sx + 1 < ED_FIELDX && lx + 1 < lev_fieldx)
2616           DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
2617         else if (sy + 1 < ED_FIELDY && ly + 1 < lev_fieldy)
2618           DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2619         else
2620           DrawLevelText(0, 0, 0, TEXT_END);
2621       }
2622       break;
2623
2624     case TEXT_BACKSPACE:
2625       if (sx > start_sx)
2626       {
2627         Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
2628         DrawMiniElement(sx - 1, sy, new_element3);
2629         DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
2630       }
2631       break;
2632
2633     case TEXT_NEWLINE:
2634       if (sy + 1 < ED_FIELDY - 1 && ly + 1 < lev_fieldy - 1)
2635         DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2636       else
2637         DrawLevelText(0, 0, 0, TEXT_END);
2638       break;
2639
2640     case TEXT_END:
2641       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2642       DrawMiniElement(sx, sy, Feld[lx][ly]);
2643       typing = FALSE;
2644       break;
2645
2646     default:
2647       break;
2648   }
2649 }
2650
2651 static void CopyLevelToUndoBuffer(int mode)
2652 {
2653   static boolean accumulated_undo = FALSE;
2654   boolean new_undo_buffer_position = TRUE;
2655   int x, y;
2656
2657   switch (mode)
2658   {
2659     case UNDO_IMMEDIATE:
2660       accumulated_undo = FALSE;
2661       break;
2662
2663     case UNDO_ACCUMULATE:
2664       if (accumulated_undo)
2665         new_undo_buffer_position = FALSE;
2666       accumulated_undo = TRUE;
2667       break;
2668
2669     default:
2670       break;
2671   }
2672
2673   if (new_undo_buffer_position)
2674   {
2675     /* new position in undo buffer ring */
2676     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
2677
2678     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
2679       undo_buffer_steps++;
2680   }
2681
2682   for(x=0; x<lev_fieldx; x++)
2683     for(y=0; y<lev_fieldy; y++)
2684       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
2685 #if 0
2686 #ifdef DEBUG
2687   printf("level saved to undo buffer\n");
2688 #endif
2689 #endif
2690 }
2691
2692 static void RandomPlacement(int button)
2693 {
2694   int new_element;
2695   int x, y;
2696
2697   new_element = (button == 1 ? new_element1 :
2698                  button == 2 ? new_element2 :
2699                  button == 3 ? new_element3 : 0);
2700
2701   if (random_placement_method == RANDOM_USE_PERCENTAGE)
2702   {
2703     for(x=0; x<lev_fieldx; x++)
2704       for(y=0; y<lev_fieldy; y++)
2705         if (RND(100) < random_placement_percentage)
2706           Feld[x][y] = new_element;
2707   }
2708   else
2709   {
2710     int elements_left = random_placement_num_objects;
2711
2712     while (elements_left > 0)
2713     {
2714       x = RND(lev_fieldx);
2715       y = RND(lev_fieldy);
2716
2717       if (Feld[x][y] != new_element)
2718       {
2719         Feld[x][y] = new_element;
2720         elements_left--;
2721       }
2722     }
2723   }
2724
2725   DrawMiniLevel(level_xpos, level_ypos);
2726   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2727 }
2728
2729 void WrapLevel(int dx, int dy)
2730 {
2731   int wrap_dx = lev_fieldx - dx;
2732   int wrap_dy = lev_fieldy - dy;
2733   int x, y;
2734
2735   for(x=0; x<lev_fieldx; x++)
2736     for(y=0; y<lev_fieldy; y++)
2737       FieldBackup[x][y] = Feld[x][y];
2738
2739   for(x=0; x<lev_fieldx; x++)
2740     for(y=0; y<lev_fieldy; y++)
2741       Feld[x][y] =
2742         FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
2743
2744   DrawMiniLevel(level_xpos, level_ypos);
2745   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
2746 }
2747
2748 static void HandleDrawingAreas(struct GadgetInfo *gi)
2749 {
2750   static boolean started_inside_drawing_area = FALSE;
2751   static boolean draw_with_brush = FALSE;
2752   int id = gi->custom_id;
2753   boolean inside_drawing_area = !gi->event.off_borders;
2754   boolean button_press_event;
2755   boolean button_release_event;
2756   boolean draw_level = (id == ED_CTRL_ID_DRAWING_LEVEL);
2757   int new_element;
2758   int button = gi->event.button;
2759   int sx = gi->event.x, sy = gi->event.y;
2760   int min_sx = 0, min_sy = 0;
2761   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
2762   int lx, ly;
2763   int min_lx = 0, min_ly = 0;
2764   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
2765   int x, y;
2766
2767   /*
2768   if (edit_mode != ED_MODE_DRAWING)
2769     return;
2770   */
2771
2772   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
2773   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
2774
2775   /* make sure to stay inside drawing area boundaries */
2776   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
2777   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
2778
2779   if (draw_level)
2780   {
2781     /* get positions inside level field */
2782     lx = sx + level_xpos;
2783     ly = sy + level_ypos;
2784
2785     /* make sure to stay inside level field boundaries */
2786     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
2787     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
2788
2789     /* correct drawing area positions accordingly */
2790     sx = lx - level_xpos;
2791     sy = ly - level_ypos;
2792   }
2793
2794   if (button_press_event)
2795     started_inside_drawing_area = inside_drawing_area;
2796
2797   if (!started_inside_drawing_area)
2798     return;
2799
2800   if (!button && !button_release_event)
2801     return;
2802
2803   new_element = (button == 1 ? new_element1 :
2804                  button == 2 ? new_element2 :
2805                  button == 3 ? new_element3 : 0);
2806
2807   if (!draw_level && drawing_function != ED_CTRL_ID_SINGLE_ITEMS)
2808     return;
2809
2810   switch (drawing_function)
2811   {
2812     case ED_CTRL_ID_SINGLE_ITEMS:
2813       if (draw_level)
2814       {
2815         if (button_release_event)
2816           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2817
2818         if (!button)
2819           break;
2820
2821         if (new_element != Feld[lx][ly])
2822         {
2823           if (new_element == EL_SPIELFIGUR)
2824           {
2825             /* remove player at old position */
2826             for(y=0; y<lev_fieldy; y++)
2827             {
2828               for(x=0; x<lev_fieldx; x++)
2829               {
2830                 if (Feld[x][y] == EL_SPIELFIGUR || Feld[x][y] == EL_SPIELER1)
2831                 {
2832                   Feld[x][y] = EL_LEERRAUM;
2833                   if (x - level_xpos >= 0 && x - level_xpos < ED_FIELDX &&
2834                       y - level_ypos >= 0 && y - level_ypos < ED_FIELDY)
2835                     DrawMiniElement(x - level_xpos, y - level_ypos,
2836                                     EL_LEERRAUM);
2837                 }
2838               }
2839             }
2840           }
2841
2842           Feld[lx][ly] = new_element;
2843           DrawMiniElement(sx, sy, new_element);
2844         }
2845       }
2846       else
2847       {
2848         DrawMiniGraphicExt(drawto, gc,
2849                            gi->x + sx * MINI_TILEX,
2850                            gi->y + sy * MINI_TILEY,
2851                            el2gfx(new_element));
2852         DrawMiniGraphicExt(window, gc,
2853                            gi->x + sx * MINI_TILEX,
2854                            gi->y + sy * MINI_TILEY,
2855                            el2gfx(new_element));
2856
2857         if (id == ED_CTRL_ID_AMOEBA_CONTENT)
2858           level.amoebe_inhalt = new_element;
2859         else if (id >= ED_CTRL_ID_ELEMCONT_0 && id <= ED_CTRL_ID_ELEMCONT_7)
2860           level.mampfer_inhalt[id - ED_CTRL_ID_ELEMCONT_0][sx][sy] =
2861             new_element;
2862       }
2863       break;
2864
2865     case ED_CTRL_ID_CONNECTED_ITEMS:
2866       {
2867         static int last_sx = -1;
2868         static int last_sy = -1;
2869
2870         if (button_release_event)
2871           CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2872
2873         if (button)
2874         {
2875           if (!button_press_event)
2876             DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
2877
2878           last_sx = sx;
2879           last_sy = sy;
2880         }
2881       }
2882       break;
2883
2884     case ED_CTRL_ID_LINE:
2885     case ED_CTRL_ID_RECTANGLE:
2886     case ED_CTRL_ID_FILLED_BOX:
2887     case ED_CTRL_ID_BRUSH:
2888       {
2889         static int last_sx = -1;
2890         static int last_sy = -1;
2891         static int start_sx = -1;
2892         static int start_sy = -1;
2893         void (*draw_func)(int, int, int, int, int, boolean);
2894
2895         if (drawing_function == ED_CTRL_ID_LINE)
2896           draw_func = DrawLine;
2897         else if (drawing_function == ED_CTRL_ID_RECTANGLE)
2898           draw_func = DrawRectangle;
2899         else if (drawing_function == ED_CTRL_ID_FILLED_BOX)
2900           draw_func = DrawFilledBox;
2901         else
2902           draw_func = SelectArea;
2903
2904         if (button_press_event)
2905         {
2906           draw_func(sx, sy, sx, sy, new_element, FALSE);
2907           start_sx = last_sx = sx;
2908           start_sy = last_sy = sy;
2909         }
2910         else if (button_release_event)
2911         {
2912           draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
2913           if (drawing_function == ED_CTRL_ID_BRUSH)
2914           {
2915             CopyAreaToBrush(start_sx, start_sy, sx, sy);
2916             draw_with_brush = TRUE;
2917           }
2918           else
2919             CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2920         }
2921         else if (last_sx != sx || last_sy != sy)
2922         {
2923           draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
2924           draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
2925           last_sx = sx;
2926           last_sy = sy;
2927         }
2928       }
2929       break;
2930
2931     case ED_CTRL_ID_TEXT:
2932       if (button_press_event)
2933         DrawLevelText(sx, sy, 0, TEXT_INIT);
2934       break;
2935
2936     case ED_CTRL_ID_FLOOD_FILL:
2937       if (button_press_event && Feld[lx][ly] != new_element)
2938       {
2939         FloodFill(lx, ly, new_element);
2940         DrawMiniLevel(level_xpos, level_ypos);
2941         CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2942       }
2943       break;
2944
2945     case ED_CTRL_ID_PICK_ELEMENT:
2946       if (button_press_event)
2947         PickDrawingElement(button, Feld[lx][ly]);
2948       if (button_release_event)
2949         ClickOnGadget(level_editor_gadget[last_drawing_function]);
2950       break;
2951
2952     default:
2953       break;
2954   }
2955 }
2956
2957 static void HandleCounterButtons(struct GadgetInfo *gi)
2958 {
2959   int id = gi->custom_id;
2960   int button = gi->event.button;
2961   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2962
2963   switch (id)
2964   {
2965     case ED_CTRL_ID_SCORE_DOWN:
2966     case ED_CTRL_ID_SCORE_UP:
2967       *gadget_score_value += (id == ED_CTRL_ID_SCORE_DOWN ? -step : step);
2968       if (*gadget_score_value < 0)
2969         *gadget_score_value = 0;
2970       else if (*gadget_score_value > 255)
2971         *gadget_score_value = 255;
2972
2973       DrawCounterValueField(ED_COUNTER_SCORE, *gadget_score_value);
2974       break;
2975
2976     case ED_CTRL_ID_ELEMCONT_DOWN:
2977     case ED_CTRL_ID_ELEMCONT_UP:
2978       *gadget_areas_value += (id == ED_CTRL_ID_ELEMCONT_DOWN ? -step : step);
2979       if (*gadget_areas_value < 1)
2980         *gadget_areas_value = 1;
2981       else if (*gadget_areas_value > MAX_ELEMCONT)
2982         *gadget_areas_value = MAX_ELEMCONT;
2983
2984       DrawCounterValueField(ED_COUNTER_ELEMCONT, *gadget_areas_value);
2985       DrawElementContentAreas();
2986       break;
2987
2988     default:
2989       break;
2990   }
2991 }
2992
2993 static void HandleControlButtons(struct GadgetInfo *gi)
2994 {
2995   int id = gi->custom_id;
2996   int button = gi->event.button;
2997   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
2998   int new_element;
2999   int player_present = FALSE;
3000   int level_changed = FALSE;
3001   int x, y;
3002
3003   new_element = (button == 1 ? new_element1 :
3004                  button == 2 ? new_element2 :
3005                  button == 3 ? new_element3 : 0);
3006
3007   if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT)
3008     DrawLevelText(0, 0, 0, TEXT_END);
3009
3010   if (id < ED_NUM_CTRL1_BUTTONS && id != ED_CTRL_ID_PROPERTIES &&
3011       edit_mode != ED_MODE_DRAWING)
3012   {
3013     DrawDrawingWindow();
3014     edit_mode = ED_MODE_DRAWING;
3015   }
3016
3017   switch (id)
3018   {
3019     case ED_CTRL_ID_SCROLL_LEFT:
3020       if (level_xpos >= 0)
3021       {
3022         int gadget_id = ED_CTRL_ID_SCROLL_HORIZONTAL;
3023         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3024         struct GadgetScrollbar *gs = &gi->scrollbar;
3025
3026         if (lev_fieldx < ED_FIELDX - 2)
3027           break;
3028
3029         level_xpos -= step;
3030         if (level_xpos < -1)
3031           level_xpos = -1;
3032         if (button == 1)
3033           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
3034         else
3035           DrawMiniLevel(level_xpos, level_ypos);
3036
3037         AdjustScrollbar(gi, gs->items_max, level_xpos + 1);
3038       }
3039       break;
3040
3041     case ED_CTRL_ID_SCROLL_RIGHT:
3042       if (level_xpos <= lev_fieldx - ED_FIELDX)
3043       {
3044         int gadget_id = ED_CTRL_ID_SCROLL_HORIZONTAL;
3045         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3046         struct GadgetScrollbar *gs = &gi->scrollbar;
3047
3048         if (lev_fieldx < ED_FIELDX - 2)
3049           break;
3050
3051         level_xpos += step;
3052         if (level_xpos > lev_fieldx - ED_FIELDX + 1)
3053           level_xpos = lev_fieldx - ED_FIELDX + 1;
3054         if (button == 1)
3055           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
3056         else
3057           DrawMiniLevel(level_xpos, level_ypos);
3058
3059         AdjustScrollbar(gi, gs->items_max, level_xpos + 1);
3060       }
3061       break;
3062
3063     case ED_CTRL_ID_SCROLL_UP:
3064       if (level_ypos >= 0)
3065       {
3066         int gadget_id = ED_CTRL_ID_SCROLL_VERTICAL;
3067         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3068         struct GadgetScrollbar *gs = &gi->scrollbar;
3069
3070         if (lev_fieldy < ED_FIELDY - 2)
3071           break;
3072
3073         level_ypos -= step;
3074         if (level_ypos < -1)
3075           level_ypos = -1;
3076         if (button == 1)
3077           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
3078         else
3079           DrawMiniLevel(level_xpos, level_ypos);
3080
3081         AdjustScrollbar(gi, gs->items_max, level_ypos + 1);
3082       }
3083       break;
3084
3085     case ED_CTRL_ID_SCROLL_DOWN:
3086       if (level_ypos <= lev_fieldy - ED_FIELDY)
3087       {
3088         int gadget_id = ED_CTRL_ID_SCROLL_VERTICAL;
3089         struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3090         struct GadgetScrollbar *gs = &gi->scrollbar;
3091
3092         if (lev_fieldy < ED_FIELDY - 2)
3093           break;
3094
3095         level_ypos += step;
3096         if (level_ypos > lev_fieldy - ED_FIELDY + 1)
3097           level_ypos = lev_fieldy - ED_FIELDY + 1;
3098         if (button == 1)
3099           ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
3100         else
3101           DrawMiniLevel(level_xpos, level_ypos);
3102
3103         AdjustScrollbar(gi, gs->items_max, level_ypos + 1);
3104       }
3105       break;
3106
3107     case ED_CTRL_ID_SCROLL_HORIZONTAL:
3108       level_xpos = gi->event.item_position - 1;
3109       DrawMiniLevel(level_xpos, level_ypos);
3110       break;
3111
3112     case ED_CTRL_ID_SCROLL_VERTICAL:
3113       level_ypos = gi->event.item_position - 1;
3114       DrawMiniLevel(level_xpos, level_ypos);
3115       break;
3116
3117     case ED_CTRL_ID_WRAP_LEFT:
3118       WrapLevel(-step, 0);
3119       break;
3120
3121     case ED_CTRL_ID_WRAP_RIGHT:
3122       WrapLevel(step, 0);
3123       break;
3124
3125     case ED_CTRL_ID_WRAP_UP:
3126       WrapLevel(0, -step);
3127       break;
3128
3129     case ED_CTRL_ID_WRAP_DOWN:
3130       WrapLevel(0, step);
3131       break;
3132
3133     case ED_CTRL_ID_SINGLE_ITEMS:
3134     case ED_CTRL_ID_CONNECTED_ITEMS:
3135     case ED_CTRL_ID_LINE:
3136     case ED_CTRL_ID_TEXT:
3137     case ED_CTRL_ID_RECTANGLE:
3138     case ED_CTRL_ID_FILLED_BOX:
3139     case ED_CTRL_ID_FLOOD_FILL:
3140     case ED_CTRL_ID_BRUSH:
3141     case ED_CTRL_ID_PICK_ELEMENT:
3142       last_drawing_function = drawing_function;
3143       drawing_function = id;
3144       break;
3145
3146     case ED_CTRL_ID_RANDOM_PLACEMENT:
3147       RandomPlacement(button);
3148       break;
3149
3150     case ED_CTRL_ID_PROPERTIES:
3151       if (edit_mode != ED_MODE_PROPERTIES)
3152       {
3153         properties_element = new_element;
3154         DrawPropertiesWindow();
3155         edit_mode = ED_MODE_PROPERTIES;
3156       }
3157       else
3158       {
3159         DrawDrawingWindow();
3160         edit_mode = ED_MODE_DRAWING;
3161       }
3162       break;
3163
3164     case ED_CTRL_ID_UNDO:
3165       if (undo_buffer_steps == 0)
3166       {
3167         Request("Undo buffer empty !", REQ_CONFIRM);
3168         break;
3169       }
3170
3171       undo_buffer_position =
3172         (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
3173       undo_buffer_steps--;
3174
3175       for(x=0; x<lev_fieldx; x++)
3176         for(y=0; y<lev_fieldy; y++)
3177           Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
3178       DrawMiniLevel(level_xpos,level_ypos);
3179       break;
3180
3181     case ED_CTRL_ID_INFO:
3182       if (edit_mode != ED_MODE_INFO)
3183       {
3184         DrawControlWindow();
3185         edit_mode = ED_MODE_INFO;
3186       }
3187       else
3188       {
3189         DrawDrawingWindow();
3190         edit_mode = ED_MODE_DRAWING;
3191       }
3192       break;
3193
3194     case ED_CTRL_ID_CLEAR:
3195       for(x=0; x<MAX_LEV_FIELDX; x++) 
3196         for(y=0; y<MAX_LEV_FIELDY; y++) 
3197           Feld[x][y] = new_element3;
3198       CopyLevelToUndoBuffer(ED_CTRL_ID_CLEAR);
3199
3200       DrawMiniLevel(level_xpos, level_ypos);
3201       break;
3202
3203     case ED_CTRL_ID_SAVE:
3204       if (leveldir[leveldir_nr].readonly)
3205       {
3206         Request("This level is read only !", REQ_CONFIRM);
3207         break;
3208       }
3209
3210       for(y=0; y<lev_fieldy; y++) 
3211         for(x=0; x<lev_fieldx; x++)
3212           if (Feld[x][y] != Ur[x][y])
3213             level_changed = TRUE;
3214
3215       if (0 && !level_changed)
3216       {
3217         Request("Level has not changed !", REQ_CONFIRM);
3218         break;
3219       }
3220
3221       for(y=0; y<lev_fieldy; y++) 
3222         for(x=0; x<lev_fieldx; x++)
3223           if (Feld[x][y] == EL_SPIELFIGUR ||
3224               Feld[x][y] == EL_SPIELER1 ||
3225               Feld[x][y] == EL_SP_MURPHY) 
3226             player_present = TRUE;
3227
3228       if (!player_present)
3229         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3230       else
3231       {
3232         if (Request("Save this level and kill the old ?", REQ_ASK))
3233         {
3234           for(x=0; x<lev_fieldx; x++)
3235             for(y=0; y<lev_fieldy; y++) 
3236               Ur[x][y] = Feld[x][y];
3237           SaveLevel(level_nr);
3238         }
3239       }
3240       break;
3241
3242     case ED_CTRL_ID_TEST:
3243       for(y=0; y<lev_fieldy; y++) 
3244         for(x=0; x<lev_fieldx; x++)
3245           if (Feld[x][y] == EL_SPIELFIGUR ||
3246               Feld[x][y] == EL_SPIELER1 ||
3247               Feld[x][y] == EL_SP_MURPHY) 
3248             player_present = TRUE;
3249
3250       if (!player_present)
3251         Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3252       else
3253       {
3254         for(x=0; x<lev_fieldx; x++)
3255           for(y=0; y<lev_fieldy; y++)
3256             FieldBackup[x][y] = Ur[x][y];
3257
3258         for(x=0; x<lev_fieldx; x++)
3259           for(y=0; y<lev_fieldy; y++)
3260             Ur[x][y] = Feld[x][y];
3261
3262         UnmapLevelEditorGadgets();
3263
3264         /* draw smaller door */
3265         XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3266                   DOOR_GFX_PAGEX7, 64,
3267                   108, 64,
3268                   EX - 4, EY - 12);
3269         redraw_mask |= REDRAW_ALL;
3270
3271         CloseDoor(DOOR_CLOSE_ALL);
3272
3273         DrawCompleteVideoDisplay();
3274
3275         if (setup.autorecord)
3276           TapeStartRecording();
3277
3278         level_editor_test_game = TRUE;
3279         game_status = PLAYING;
3280
3281         InitGame();
3282       }
3283       break;
3284
3285     case ED_CTRL_ID_EXIT:
3286       for(y=0; y<lev_fieldy; y++) 
3287         for(x=0; x<lev_fieldx; x++)
3288           if (Feld[x][y] != Ur[x][y])
3289             level_changed = TRUE;
3290
3291       if (!level_changed ||
3292           Request("Level has changed! Exit without saving ?",
3293                   REQ_ASK | REQ_STAY_OPEN))
3294       {
3295         CloseDoor(DOOR_CLOSE_1);
3296
3297         /*
3298         CloseDoor(DOOR_CLOSE_ALL);
3299         */
3300
3301         /* draw smaller door */
3302         XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3303                   DOOR_GFX_PAGEX7, 64,
3304                   108, 64,
3305                   EX - 4, EY - 12);
3306         redraw_mask |= REDRAW_ALL;
3307
3308         game_status = MAINMENU;
3309         DrawMainMenu();
3310       }
3311       else
3312       {
3313         CloseDoor(DOOR_CLOSE_1);
3314         XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
3315                   DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
3316                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3317         OpenDoor(DOOR_OPEN_1);
3318       }
3319       break;
3320
3321     default:
3322 #ifdef DEBUG
3323       if (gi->event.type == GD_EVENT_PRESSED)
3324         printf("default: HandleControlButtons: GD_EVENT_PRESSED\n");
3325       else if (gi->event.type == GD_EVENT_RELEASED)
3326         printf("default: HandleControlButtons: GD_EVENT_RELEASED\n");
3327       else if (gi->event.type == GD_EVENT_MOVING)
3328         printf("default: HandleControlButtons: GD_EVENT_MOVING\n");
3329       else
3330         printf("default: HandleControlButtons: ?\n");
3331 #endif
3332       break;
3333   }
3334 }
3335
3336 void HandleLevelEditorKeyInput(KeySym key)
3337 {
3338   if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT)
3339   {
3340     char letter = getCharFromKeySym(key);
3341
3342     /* map lower case letters to upper case */
3343     if (letter >= 'a' && letter <= 'z')
3344       letter += (int)('A' - 'a');
3345     else if (letter == 'ä')
3346       letter = 'Ä';
3347     else if (letter == 'ä')
3348       letter = 'Ö';
3349     else if (letter == 'ä')
3350       letter = 'Ü';
3351
3352     if (letter)
3353       DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
3354     else if (key == XK_Delete || key == XK_BackSpace)
3355       DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
3356     else if (key == XK_Return)
3357       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
3358   }
3359 }
3360
3361 static void HandleTextInputGadgets(struct GadgetInfo *gi)
3362 {
3363   int id = gi->custom_id;
3364
3365   switch (id)
3366   {
3367     case ED_CTRL_ID_LEVEL_NAME:
3368       strcpy(level.name, gi->text_value);
3369       break;
3370
3371     default:
3372       break;
3373   }
3374 }