1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
10 *----------------------------------------------------------*
12 ***********************************************************/
25 /* positions in the level editor */
26 #define ED_WIN_MB_LEFT_XPOS 7
27 #define ED_WIN_MB_LEFT_YPOS 6
28 #define ED_WIN_LEVELNR_XPOS 77
29 #define ED_WIN_LEVELNR_YPOS 7
30 #define ED_WIN_MB_MIDDLE_XPOS 7
31 #define ED_WIN_MB_MIDDLE_YPOS 258
32 #define ED_WIN_MB_RIGHT_XPOS 77
33 #define ED_WIN_MB_RIGHT_YPOS 258
35 /* other constants for the editor */
36 #define ED_SCROLL_NO 0
37 #define ED_SCROLL_LEFT 1
38 #define ED_SCROLL_RIGHT 2
39 #define ED_SCROLL_UP 4
40 #define ED_SCROLL_DOWN 8
42 /* screens in the level editor */
43 #define ED_MODE_DRAWING 0
44 #define ED_MODE_INFO 1
45 #define ED_MODE_PROPERTIES 2
47 /* how many steps can be cancelled */
48 #define NUM_UNDO_STEPS (10 + 1)
50 /* values for random placement */
51 #define RANDOM_USE_PERCENTAGE 0
52 #define RANDOM_USE_NUM_OBJECTS 1
54 /* values for elements with score */
58 /* values for elements with content */
59 #define MIN_ELEM_CONTENT 1
60 #define MAX_ELEM_CONTENT 8
62 /* values for the control window */
63 #define ED_CTRL_BUTTONS_GFX_YPOS 236
64 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS 142
66 #define ED_CTRL1_BUTTONS_HORIZ 4
67 #define ED_CTRL1_BUTTONS_VERT 4
68 #define ED_CTRL1_BUTTON_XSIZE 22
69 #define ED_CTRL1_BUTTON_YSIZE 22
70 #define ED_CTRL1_BUTTONS_XPOS 6
71 #define ED_CTRL1_BUTTONS_YPOS 6
72 #define ED_CTRL2_BUTTONS_HORIZ 3
73 #define ED_CTRL2_BUTTONS_VERT 2
74 #define ED_CTRL2_BUTTON_XSIZE 30
75 #define ED_CTRL2_BUTTON_YSIZE 20
76 #define ED_CTRL2_BUTTONS_XPOS 5
77 #define ED_CTRL2_BUTTONS_YPOS 99
78 #define ED_NUM_CTRL1_BUTTONS (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
79 #define ED_NUM_CTRL2_BUTTONS (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
80 #define ED_NUM_CTRL_BUTTONS (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
82 /* values for the element list */
83 #define ED_ELEMENTLIST_UP_XPOS 35
84 #define ED_ELEMENTLIST_UP_YPOS 5
85 #define ED_ELEMENTLIST_UP_ALT_YPOS 140
86 #define ED_ELEMENTLIST_DOWN_XPOS 35
87 #define ED_ELEMENTLIST_DOWN_YPOS 250
88 #define ED_ELEMENTLIST_DOWN_ALT_YPOS 165
89 #define ED_ELEMENTLIST_UPDOWN_XSIZE 30
90 #define ED_ELEMENTLIST_UPDOWN_YSIZE 25
91 #define ED_ELEMENTLIST_XPOS 6
92 #define ED_ELEMENTLIST_YPOS 30
93 #define ED_ELEMENTLIST_ALT_YPOS 190
94 #define ED_ELEMENTLIST_XSIZE 22
95 #define ED_ELEMENTLIST_YSIZE 22
96 #define ED_ELEMENTLIST_BUTTONS_HORIZ 4
97 #define ED_ELEMENTLIST_BUTTONS_VERT 10
98 #define ED_NUM_ELEMENTLIST_BUTTONS (ED_ELEMENTLIST_BUTTONS_HORIZ * \
99 ED_ELEMENTLIST_BUTTONS_VERT)
101 /* values for element properties window */
102 #define ED_PROPERTIES_XPOS (TILEX - MINI_TILEX/2)
104 /* values for level information window */
105 #define ED_LEVELINFO_XPOS (TILEX - MINI_TILEX/2)
106 #define ED_LEVELINFO_YPOS (TILEY - MINI_TILEY/2)
108 /* values for counter gadgets */
109 #define ED_COUNT_VALUE_XOFFSET 5
110 #define ED_COUNT_VALUE_YOFFSET 3
111 #define ED_COUNT_ELEM_SCORE_XPOS ED_PROPERTIES_XPOS
112 #define ED_COUNT_ELEM_SCORE_YPOS (14 * MINI_TILEY)
113 #define ED_COUNT_ELEM_CONTENT_XPOS ED_PROPERTIES_XPOS
114 #define ED_COUNT_ELEM_CONTENT_YPOS (17 * MINI_TILEY)
115 #define ED_COUNTER_YSTART (ED_LEVELINFO_YPOS + 3 * TILEY)
116 #define ED_COUNTER_YDISTANCE (3 * MINI_TILEY)
117 #define ED_COUNTER_YPOS(n) (ED_COUNTER_YSTART + \
118 n * ED_COUNTER_YDISTANCE)
119 /* standard distances */
120 #define ED_BORDER_SIZE 3
121 #define ED_GADGET_DISTANCE 2
123 /* values for element content drawing areas */
124 #define ED_AREA_ELEM_CONTENT_XPOS (TILEX)
125 #define ED_AREA_ELEM_CONTENT_YPOS (10 * TILEY)
127 /* values for scrolling gadgets */
128 #define ED_SCROLLBUTTON_XPOS 24
129 #define ED_SCROLLBUTTON_YPOS 0
130 #define ED_SCROLLBAR_XPOS 24
131 #define ED_SCROLLBAR_YPOS 64
133 #define ED_SCROLLBUTTON_XSIZE 16
134 #define ED_SCROLLBUTTON_YSIZE 16
136 #define ED_SCROLL_UP_XPOS (SXSIZE - ED_SCROLLBUTTON_XSIZE)
137 #define ED_SCROLL_UP_YPOS (0)
138 #define ED_SCROLL_DOWN_XPOS ED_SCROLL_UP_XPOS
139 #define ED_SCROLL_DOWN_YPOS (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
140 #define ED_SCROLL_LEFT_XPOS (0)
141 #define ED_SCROLL_LEFT_YPOS (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
142 #define ED_SCROLL_RIGHT_XPOS (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
143 #define ED_SCROLL_RIGHT_YPOS ED_SCROLL_LEFT_YPOS
144 #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + ED_SCROLLBUTTON_XSIZE)
145 #define ED_SCROLL_HORIZONTAL_YPOS ED_SCROLL_LEFT_YPOS
146 #define ED_SCROLL_HORIZONTAL_XSIZE (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
147 #define ED_SCROLL_HORIZONTAL_YSIZE ED_SCROLLBUTTON_YSIZE
148 #define ED_SCROLL_VERTICAL_XPOS ED_SCROLL_UP_XPOS
149 #define ED_SCROLL_VERTICAL_YPOS (ED_SCROLL_UP_YPOS + ED_SCROLLBUTTON_YSIZE)
150 #define ED_SCROLL_VERTICAL_XSIZE ED_SCROLLBUTTON_XSIZE
151 #define ED_SCROLL_VERTICAL_YSIZE (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
153 /* control button identifiers */
154 #define GADGET_ID_NONE -1
156 #define GADGET_ID_SINGLE_ITEMS 0
157 #define GADGET_ID_CONNECTED_ITEMS 1
158 #define GADGET_ID_LINE 2
159 #define GADGET_ID_ARC 3
160 #define GADGET_ID_RECTANGLE 4
161 #define GADGET_ID_FILLED_BOX 5
162 #define GADGET_ID_WRAP_UP 6
163 #define GADGET_ID_TEXT 7
164 #define GADGET_ID_FLOOD_FILL 8
165 #define GADGET_ID_WRAP_LEFT 9
166 #define GADGET_ID_PROPERTIES 10
167 #define GADGET_ID_WRAP_RIGHT 11
168 #define GADGET_ID_RANDOM_PLACEMENT 12
169 #define GADGET_ID_GRAB_BRUSH 13
170 #define GADGET_ID_WRAP_DOWN 14
171 #define GADGET_ID_PICK_ELEMENT 15
172 #define GADGET_ID_UNDO 16
173 #define GADGET_ID_INFO 17
174 #define GADGET_ID_SAVE 18
175 #define GADGET_ID_CLEAR 19
176 #define GADGET_ID_TEST 20
177 #define GADGET_ID_EXIT 21
179 /* counter button identifiers */
180 #define GADGET_ID_ELEM_SCORE_DOWN 22
181 #define GADGET_ID_ELEM_SCORE_TEXT 23
182 #define GADGET_ID_ELEM_SCORE_UP 24
183 #define GADGET_ID_ELEM_CONTENT_DOWN 25
184 #define GADGET_ID_ELEM_CONTENT_TEXT 26
185 #define GADGET_ID_ELEM_CONTENT_UP 27
186 #define GADGET_ID_LEVEL_XSIZE_DOWN 28
187 #define GADGET_ID_LEVEL_XSIZE_TEXT 29
188 #define GADGET_ID_LEVEL_XSIZE_UP 30
189 #define GADGET_ID_LEVEL_YSIZE_DOWN 31
190 #define GADGET_ID_LEVEL_YSIZE_TEXT 32
191 #define GADGET_ID_LEVEL_YSIZE_UP 33
192 #define GADGET_ID_LEVEL_RANDOM_DOWN 34
193 #define GADGET_ID_LEVEL_RANDOM_TEXT 35
194 #define GADGET_ID_LEVEL_RANDOM_UP 36
195 #define GADGET_ID_LEVEL_COLLECT_DOWN 37
196 #define GADGET_ID_LEVEL_COLLECT_TEXT 38
197 #define GADGET_ID_LEVEL_COLLECT_UP 39
198 #define GADGET_ID_LEVEL_TIMELIMIT_DOWN 40
199 #define GADGET_ID_LEVEL_TIMELIMIT_TEXT 41
200 #define GADGET_ID_LEVEL_TIMELIMIT_UP 42
201 #define GADGET_ID_LEVEL_TIMESCORE_DOWN 43
202 #define GADGET_ID_LEVEL_TIMESCORE_TEXT 44
203 #define GADGET_ID_LEVEL_TIMESCORE_UP 45
205 /* drawing area identifiers */
206 #define GADGET_ID_DRAWING_LEVEL 46
207 #define GADGET_ID_ELEM_CONTENT_0 47
208 #define GADGET_ID_ELEM_CONTENT_1 48
209 #define GADGET_ID_ELEM_CONTENT_2 49
210 #define GADGET_ID_ELEM_CONTENT_3 50
211 #define GADGET_ID_ELEM_CONTENT_4 51
212 #define GADGET_ID_ELEM_CONTENT_5 52
213 #define GADGET_ID_ELEM_CONTENT_6 53
214 #define GADGET_ID_ELEM_CONTENT_7 54
215 #define GADGET_ID_AMOEBA_CONTENT 55
217 /* text input identifiers */
218 #define GADGET_ID_LEVEL_NAME 56
219 #define GADGET_ID_LEVEL_AUTHOR 57
221 /* gadgets for scrolling of drawing area */
222 #define GADGET_ID_SCROLL_UP 58
223 #define GADGET_ID_SCROLL_DOWN 59
224 #define GADGET_ID_SCROLL_LEFT 60
225 #define GADGET_ID_SCROLL_RIGHT 61
226 #define GADGET_ID_SCROLL_HORIZONTAL 62
227 #define GADGET_ID_SCROLL_VERTICAL 63
229 /* gadgets for scrolling element list */
230 #define GADGET_ID_ELEMENTLIST_UP 64
231 #define GADGET_ID_ELEMENTLIST_DOWN 65
233 /* gadgets for buttons in element list */
234 #define GADGET_ID_ELEMENTLIST_FIRST 66
235 #define GADGET_ID_ELEMENTLIST_LAST 105
237 #define NUM_EDITOR_GADGETS 106
239 /* values for counter gadgets */
240 #define ED_COUNTER_ID_ELEM_SCORE 0
241 #define ED_COUNTER_ID_ELEM_CONTENT 1
242 #define ED_COUNTER_ID_LEVEL_XSIZE 2
243 #define ED_COUNTER_ID_LEVEL_YSIZE 3
244 #define ED_COUNTER_ID_LEVEL_RANDOM 4
245 #define ED_COUNTER_ID_LEVEL_COLLECT 5
246 #define ED_COUNTER_ID_LEVEL_TIMELIMIT 6
247 #define ED_COUNTER_ID_LEVEL_TIMESCORE 7
249 #define ED_NUM_COUNTERBUTTONS 8
251 /* values for scrollbutton gadgets */
252 #define ED_SCROLLBUTTON_AREA_UP 0
253 #define ED_SCROLLBUTTON_AREA_DOWN 1
254 #define ED_SCROLLBUTTON_AREA_LEFT 2
255 #define ED_SCROLLBUTTON_AREA_RIGHT 3
256 #define ED_SCROLLBUTTON_LIST_UP 4
257 #define ED_SCROLLBUTTON_LIST_DOWN 5
259 #define ED_NUM_SCROLLBUTTONS 6
261 /* values for scrollbar gadgets */
262 #define ED_SCROLLBAR_HORIZONTAL 0
263 #define ED_SCROLLBAR_VERTICAL 1
265 #define ED_NUM_SCROLLBARS 2
267 /* values for text input gadgets */
268 #define ED_TEXTINPUT_ID_LEVEL_NAME 0
269 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR 1
271 #define ED_NUM_TEXTINPUT 2
273 /* values for CopyLevelToUndoBuffer() */
274 #define UNDO_IMMEDIATE 0
275 #define UNDO_ACCUMULATE 1
277 /* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
278 #define INFOTEXT_XPOS SX
279 #define INFOTEXT_YPOS (SY + SYSIZE - MINI_TILEX + 2)
280 #define INFOTEXT_XSIZE SXSIZE
281 #define INFOTEXT_YSIZE MINI_TILEX
282 #define MAX_INFOTEXT_LEN (SXSIZE / FONT2_XSIZE)
288 } control_info[ED_NUM_CTRL_BUTTONS] =
290 { 's', "draw single items" },
291 { 'd', "draw connected items" },
292 { 'l', "draw lines" },
293 { 'a', "draw arcs" },
294 { 'r', "draw outline rectangles" },
295 { 'R', "draw filled rectangles" },
296 { '\0', "wrap (rotate) level up" },
297 { 't', "enter text elements" },
298 { 'f', "flood fill" },
299 { '\0', "wrap (rotate) level left" },
300 { '?', "properties of drawing element" },
301 { '\0', "wrap (rotate) level right" },
302 { '\0', "random element placement" },
303 { 'b', "grab brush" },
304 { '\0', "wrap (rotate) level down" },
305 { ',', "pick drawing element" },
306 { 'U', "undo last operation" },
307 { 'I', "level properties" },
308 { 'S', "save level" },
309 { 'C', "clear level" },
310 { 'T', "test level" },
311 { 'E', "exit level editor" }
314 /* pointers to counter values */
315 static int *gadget_elem_score_value = NULL;
316 static int *gadget_elem_content_value = NULL;
317 static int *gadget_level_xsize_value = NULL;
318 static int *gadget_level_ysize_value = NULL;
319 static int *gadget_level_random_value = NULL;
320 static int *gadget_level_collect_value = NULL;
321 static int *gadget_level_timelimit_value = NULL;
322 static int *gadget_level_timescore_value = NULL;
327 int min_value, max_value;
328 int gadget_id_down, gadget_id_up;
332 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
335 ED_COUNT_ELEM_SCORE_XPOS, ED_COUNT_ELEM_SCORE_YPOS,
336 MIN_SCORE, MAX_SCORE,
337 GADGET_ID_ELEM_SCORE_DOWN, GADGET_ID_ELEM_SCORE_UP,
338 GADGET_ID_ELEM_SCORE_TEXT,
339 &gadget_elem_score_value,
343 ED_COUNT_ELEM_CONTENT_XPOS, ED_COUNT_ELEM_CONTENT_YPOS,
344 MIN_ELEM_CONTENT, MAX_ELEM_CONTENT,
345 GADGET_ID_ELEM_CONTENT_DOWN, GADGET_ID_ELEM_CONTENT_UP,
346 GADGET_ID_ELEM_CONTENT_TEXT,
347 &gadget_elem_content_value,
351 ED_LEVELINFO_XPOS, ED_COUNTER_YPOS(0),
352 MIN_LEV_FIELDX, MAX_LEV_FIELDX,
353 GADGET_ID_LEVEL_XSIZE_DOWN, GADGET_ID_LEVEL_XSIZE_UP,
354 GADGET_ID_LEVEL_XSIZE_TEXT,
355 &gadget_level_xsize_value,
359 ED_LEVELINFO_XPOS, ED_COUNTER_YPOS(1),
360 MIN_LEV_FIELDY, MAX_LEV_FIELDY,
361 GADGET_ID_LEVEL_YSIZE_DOWN, GADGET_ID_LEVEL_YSIZE_UP,
362 GADGET_ID_LEVEL_YSIZE_TEXT,
363 &gadget_level_ysize_value,
367 ED_LEVELINFO_XPOS, ED_COUNTER_YPOS(2),
369 GADGET_ID_LEVEL_RANDOM_DOWN, GADGET_ID_LEVEL_RANDOM_UP,
370 GADGET_ID_LEVEL_RANDOM_TEXT,
371 &gadget_level_random_value,
372 "number of random elements"
375 ED_LEVELINFO_XPOS, ED_COUNTER_YPOS(3),
377 GADGET_ID_LEVEL_COLLECT_DOWN, GADGET_ID_LEVEL_COLLECT_UP,
378 GADGET_ID_LEVEL_COLLECT_TEXT,
379 &gadget_level_collect_value,
380 "number of emeralds to collect"
383 ED_LEVELINFO_XPOS, ED_COUNTER_YPOS(4),
385 GADGET_ID_LEVEL_TIMELIMIT_DOWN, GADGET_ID_LEVEL_TIMELIMIT_UP,
386 GADGET_ID_LEVEL_TIMELIMIT_TEXT,
387 &gadget_level_timelimit_value,
388 "time available to solve level"
391 ED_LEVELINFO_XPOS, ED_COUNTER_YPOS(5),
393 GADGET_ID_LEVEL_TIMESCORE_DOWN, GADGET_ID_LEVEL_TIMESCORE_UP,
394 GADGET_ID_LEVEL_TIMESCORE_TEXT,
395 &gadget_level_timescore_value,
396 "score for each 10 seconds left"
406 } textinput_info[ED_NUM_TEXTINPUT] =
409 ED_LEVELINFO_XPOS, ED_COUNTER_YPOS(6),
410 GADGET_ID_LEVEL_NAME,
415 ED_LEVELINFO_XPOS, ED_COUNTER_YPOS(7),
416 GADGET_ID_LEVEL_AUTHOR,
428 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
431 ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE,
432 ED_SCROLL_UP_XPOS, ED_SCROLL_UP_YPOS,
434 "scroll level editing area up"
437 ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
438 ED_SCROLL_DOWN_XPOS, ED_SCROLL_DOWN_YPOS,
439 GADGET_ID_SCROLL_DOWN,
440 "scroll level editing area down"
443 ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
444 ED_SCROLL_LEFT_XPOS, ED_SCROLL_LEFT_YPOS,
445 GADGET_ID_SCROLL_LEFT,
446 "scroll level editing area left"
449 ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
450 ED_SCROLL_RIGHT_XPOS, ED_SCROLL_RIGHT_YPOS,
451 GADGET_ID_SCROLL_RIGHT,
452 "scroll level editing area right"
455 ED_ELEMENTLIST_UP_XPOS, ED_ELEMENTLIST_UP_ALT_YPOS,
456 ED_ELEMENTLIST_UP_XPOS, ED_ELEMENTLIST_UP_YPOS,
457 GADGET_ID_ELEMENTLIST_UP,
458 "scroll element list up"
461 ED_ELEMENTLIST_DOWN_XPOS, ED_ELEMENTLIST_DOWN_ALT_YPOS,
462 ED_ELEMENTLIST_DOWN_XPOS, ED_ELEMENTLIST_DOWN_YPOS,
463 GADGET_ID_ELEMENTLIST_DOWN,
464 "scroll element list down"
476 } scrollbar_info[ED_NUM_SCROLLBARS] =
479 ED_SCROLLBAR_XPOS, ED_SCROLLBAR_YPOS,
480 ED_SCROLL_HORIZONTAL_XPOS, ED_SCROLL_HORIZONTAL_YPOS,
481 ED_SCROLL_HORIZONTAL_XSIZE, ED_SCROLL_HORIZONTAL_YSIZE,
482 GD_TYPE_SCROLLBAR_HORIZONTAL,
483 GADGET_ID_SCROLL_HORIZONTAL,
484 "scroll level editing area horizontally"
487 ED_SCROLLBAR_XPOS, ED_SCROLLBAR_YPOS,
488 ED_SCROLL_VERTICAL_XPOS, ED_SCROLL_VERTICAL_YPOS,
489 ED_SCROLL_VERTICAL_XSIZE, ED_SCROLL_VERTICAL_YSIZE,
490 GD_TYPE_SCROLLBAR_VERTICAL,
491 GADGET_ID_SCROLL_VERTICAL,
492 "scroll level editing area vertically"
496 /* maximal size of level editor drawing area */
497 #define MAX_ED_FIELDX (2 * SCR_FIELDX)
498 #define MAX_ED_FIELDY (2 * SCR_FIELDY - 1)
501 #define ED_FIELDX (2 * SCR_FIELDX - 1)
502 #define ED_FIELDY (2 * SCR_FIELDY - 2)
505 /* actual size of level editor drawing area */
506 static int ed_fieldx = MAX_ED_FIELDX - 1, ed_fieldy = MAX_ED_FIELDY - 1;
508 /* actual position of level editor drawing area in level playfield */
509 static int level_xpos = -1, level_ypos = -1;
511 #define IN_ED_FIELD(x,y) ((x)>=0 && (x)<ed_fieldx && (y)>=0 &&(y)<ed_fieldx)
513 /* forward declaration for internal use */
514 static void DrawDrawingWindow();
515 static void DrawLevelInfoWindow();
516 static void DrawPropertiesWindow();
517 static void CopyLevelToUndoBuffer(int);
518 static void HandleControlButtons(struct GadgetInfo *);
519 static void HandleCounterButtons(struct GadgetInfo *);
520 static void HandleDrawingAreas(struct GadgetInfo *);
521 static void HandleDrawingAreaInfo(struct GadgetInfo *);
522 static void HandleTextInputGadgets(struct GadgetInfo *);
524 static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
526 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
527 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
528 static boolean draw_with_brush = FALSE;
529 static int properties_element = 0;
531 static short ElementContent[MAX_ELEM_CONTENT][3][3];
532 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
533 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
534 static int undo_buffer_position = 0;
535 static int undo_buffer_steps = 0;
537 static int random_placement_percentage = 10;
538 static int random_placement_num_objects = 10;
540 static int random_placement_method = RANDOM_USE_PERCENTAGE;
542 static int random_placement_method = RANDOM_USE_NUM_OBJECTS;
545 static int edit_mode;
546 static int new_element1 = EL_MAUERWERK;
547 static int new_element2 = EL_LEERRAUM;
548 static int new_element3 = EL_ERDREICH;
550 static int counter_xsize = DXSIZE + 20;
552 int element_shift = 0;
554 int editor_element[] =
556 EL_CHAR_A + ('B' - 'A'),
557 EL_CHAR_A + ('O' - 'A'),
558 EL_CHAR_A + ('U' - 'A'),
559 EL_CHAR_A + ('L' - 'A'),
562 EL_CHAR_A + ('D' - 'A'),
563 EL_CHAR_A + ('E' - 'A'),
564 EL_CHAR_A + ('R' - 'A'),
566 EL_CHAR_A + ('D' - 'A'),
567 EL_CHAR_A + ('A' - 'A'),
568 EL_CHAR_A + ('S' - 'A'),
569 EL_CHAR_A + ('H' - 'A'),
596 EL_CHAR_A + ('E' - 'A'),
597 EL_CHAR_A + ('M' - 'A'),
598 EL_CHAR_A + ('E' - 'A'),
601 EL_CHAR_A + ('R' - 'A'),
602 EL_CHAR_A + ('A' - 'A'),
603 EL_CHAR_A + ('L' - 'A'),
604 EL_CHAR_A + ('D' - 'A'),
606 EL_CHAR_A + ('M' - 'A'),
607 EL_CHAR_A + ('I' - 'A'),
608 EL_CHAR_A + ('N' - 'A'),
609 EL_CHAR_A + ('E' - 'A'),
686 EL_CHAR_A + ('M' - 'A'),
687 EL_CHAR_A + ('O' - 'A'),
688 EL_CHAR_A + ('R' - 'A'),
689 EL_CHAR_A + ('E' - 'A'),
741 EL_CHAR_A + ('S' - 'A'),
742 EL_CHAR_A + ('O' - 'A'),
743 EL_CHAR_A + ('K' - 'A'),
744 EL_CHAR_A + ('O' - 'A'),
747 EL_CHAR_A + ('B' - 'A'),
748 EL_CHAR_A + ('A' - 'A'),
749 EL_CHAR_A + ('N' - 'A'),
752 EL_SOKOBAN_FELD_LEER,
753 EL_SOKOBAN_FELD_VOLL,
822 EL_CHAR_A + ('D' - 'A'),
823 EL_CHAR_A + ('Y' - 'A'),
824 EL_CHAR_A + ('N' - 'A'),
825 EL_CHAR_A + ('A' - 'A'),
827 EL_CHAR_A + ('B' - 'A'),
828 EL_CHAR_A + ('L' - 'A'),
829 EL_CHAR_A + ('A' - 'A'),
830 EL_CHAR_A + ('S' - 'A'),
833 EL_CHAR_A + ('T' - 'A'),
834 EL_CHAR_A + ('E' - 'A'),
835 EL_CHAR_A + ('R' - 'A'),
918 int elements_in_list = sizeof(editor_element)/sizeof(int);
920 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
923 int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
924 int dy = (scroll == ED_SCROLL_UP ? -1 : scroll == ED_SCROLL_DOWN ? 1 : 0);
926 XCopyArea(display, drawto, drawto, gc,
927 SX + (dx == -1 ? MINI_TILEX : 0),
928 SY + (dy == -1 ? MINI_TILEY : 0),
929 (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
930 (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
931 SX + (dx == +1 ? MINI_TILEX : 0),
932 SY + (dy == +1 ? MINI_TILEY : 0));
935 x = (dx == 1 ? 0 : ed_fieldx - 1);
936 for(y=0; y<ed_fieldy; y++)
937 DrawMiniElementOrWall(x, y, from_x, from_y);
941 y = (dy == 1 ? 0 : ed_fieldy - 1);
942 for(x=0; x<ed_fieldx; x++)
943 DrawMiniElementOrWall(x, y, from_x, from_y);
946 redraw_mask |= REDRAW_FIELD;
950 static void CreateControlButtons()
952 Pixmap gd_pixmap = pix[PIX_DOOR];
953 struct GadgetInfo *gi;
954 unsigned long event_mask;
957 /* create toolbox buttons */
958 for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
962 int gd_xoffset, gd_yoffset;
963 int gd_x1, gd_x2, gd_y1, gd_y2;
968 if (id == GADGET_ID_SINGLE_ITEMS ||
969 id == GADGET_ID_CONNECTED_ITEMS ||
970 id == GADGET_ID_LINE ||
971 id == GADGET_ID_ARC ||
972 id == GADGET_ID_TEXT ||
973 id == GADGET_ID_RECTANGLE ||
974 id == GADGET_ID_FILLED_BOX ||
975 id == GADGET_ID_FLOOD_FILL ||
976 id == GADGET_ID_GRAB_BRUSH ||
977 id == GADGET_ID_PICK_ELEMENT)
979 button_type = GD_TYPE_RADIO_BUTTON;
981 checked = (id == drawing_function ? TRUE : FALSE);
982 event_mask = GD_EVENT_PRESSED;
986 button_type = GD_TYPE_NORMAL_BUTTON;
990 if (id == GADGET_ID_WRAP_LEFT ||
991 id == GADGET_ID_WRAP_RIGHT ||
992 id == GADGET_ID_WRAP_UP ||
993 id == GADGET_ID_WRAP_DOWN)
994 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
996 event_mask = GD_EVENT_RELEASED;
999 if (id < ED_NUM_CTRL1_BUTTONS)
1001 int x = i % ED_CTRL1_BUTTONS_HORIZ;
1002 int y = i / ED_CTRL1_BUTTONS_HORIZ;
1004 gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
1005 gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
1006 width = ED_CTRL1_BUTTON_XSIZE;
1007 height = ED_CTRL1_BUTTON_YSIZE;
1011 int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
1012 int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
1014 gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
1015 gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
1016 width = ED_CTRL2_BUTTON_XSIZE;
1017 height = ED_CTRL2_BUTTON_YSIZE;
1020 gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
1021 gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
1022 gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_GFX_YPOS + gd_yoffset;
1023 gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
1025 gi = CreateGadget(GDI_CUSTOM_ID, id,
1026 GDI_INFO_TEXT, control_info[i].text,
1027 GDI_X, EX + gd_xoffset,
1028 GDI_Y, EY + gd_yoffset,
1031 GDI_TYPE, button_type,
1032 GDI_STATE, GD_BUTTON_UNPRESSED,
1033 GDI_RADIO_NR, radio_button_nr,
1034 GDI_CHECKED, checked,
1035 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1036 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
1037 GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
1038 GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1039 GDI_EVENT_MASK, event_mask,
1040 GDI_CALLBACK_ACTION, HandleControlButtons,
1044 Error(ERR_EXIT, "cannot create gadget");
1046 level_editor_gadget[id] = gi;
1049 /* create buttons for scrolling of drawing area and element list */
1050 for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
1052 int id = scrollbutton_info[i].gadget_id;
1053 int x, y, width, height;
1054 int gd_x1, gd_x2, gd_y1, gd_y2;
1056 x = scrollbutton_info[i].x;
1057 y = scrollbutton_info[i].y;
1059 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
1061 if (id == GADGET_ID_ELEMENTLIST_UP ||
1062 id == GADGET_ID_ELEMENTLIST_DOWN)
1066 width = ED_ELEMENTLIST_UPDOWN_XSIZE;
1067 height = ED_ELEMENTLIST_UPDOWN_YSIZE;
1068 gd_x1 = DOOR_GFX_PAGEX6 + scrollbutton_info[i].xpos;
1069 gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].y;
1071 gd_y2 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
1077 width = ED_SCROLLBUTTON_XSIZE;
1078 height = ED_SCROLLBUTTON_YSIZE;
1079 gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].xpos;
1080 gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
1081 gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
1085 gi = CreateGadget(GDI_CUSTOM_ID, id,
1086 GDI_INFO_TEXT, scrollbutton_info[i].infotext,
1091 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1092 GDI_STATE, GD_BUTTON_UNPRESSED,
1093 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1094 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1095 GDI_EVENT_MASK, event_mask,
1096 GDI_CALLBACK_ACTION, HandleControlButtons,
1100 Error(ERR_EXIT, "cannot create gadget");
1102 level_editor_gadget[id] = gi;
1105 /* create buttons for element list */
1106 for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
1109 int deco_x, deco_y, deco_xpos, deco_ypos;
1110 int gd_xoffset, gd_yoffset;
1111 int gd_x, gd_y1, gd_y2;
1112 int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
1113 int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
1114 int id = GADGET_ID_ELEMENTLIST_FIRST + i;
1116 event_mask = GD_EVENT_RELEASED;
1118 gd_xoffset = ED_ELEMENTLIST_XPOS + x * ED_ELEMENTLIST_XSIZE;
1119 gd_yoffset = ED_ELEMENTLIST_YPOS + y * ED_ELEMENTLIST_YSIZE;
1121 gd_x = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
1122 gd_y1 = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
1123 gd_y2 = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_ALT_YPOS;
1125 getMiniGraphicSource(el2gfx(editor_element[i]),
1126 &deco_pixmap, &deco_x, &deco_y);
1127 deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2;
1128 deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
1130 gi = CreateGadget(GDI_CUSTOM_ID, id,
1131 GDI_INFO_TEXT, "choose element",
1132 GDI_X, DX + gd_xoffset,
1133 GDI_Y, DY + gd_yoffset,
1134 GDI_WIDTH, ED_ELEMENTLIST_XSIZE,
1135 GDI_HEIGHT, ED_ELEMENTLIST_YSIZE,
1136 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1137 GDI_STATE, GD_BUTTON_UNPRESSED,
1138 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y1,
1139 GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y2,
1140 GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
1141 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
1142 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
1143 GDI_DECORATION_SHIFTING, 1, 1,
1144 GDI_EVENT_MASK, event_mask,
1145 GDI_CALLBACK_ACTION, HandleControlButtons,
1149 Error(ERR_EXIT, "cannot create gadget");
1151 level_editor_gadget[id] = gi;
1155 static void CreateCounterButtons()
1159 for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
1162 int xpos = SX + counterbutton_info[i].x; /* xpos of down count button */
1163 int ypos = SY + counterbutton_info[i].y;
1167 Pixmap gd_pixmap = pix[PIX_DOOR];
1168 struct GadgetInfo *gi;
1170 counterbutton_info[i].gadget_id_down :
1171 counterbutton_info[i].gadget_id_up);
1173 int gd_x, gd_x1, gd_x2, gd_y;
1174 unsigned long event_mask;
1175 char infotext[MAX_INFOTEXT_LEN + 1];
1177 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
1179 gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
1180 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
1181 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
1182 gd_y = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
1184 sprintf(infotext, "%s counter value by 1, 5 or 10",
1185 (j == 0 ? "decrease" : "increase"));
1187 gi = CreateGadget(GDI_CUSTOM_ID, id,
1188 GDI_INFO_TEXT, infotext,
1191 GDI_WIDTH, ED_BUTTON_COUNT_XSIZE,
1192 GDI_HEIGHT, ED_BUTTON_COUNT_YSIZE,
1193 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1194 GDI_STATE, GD_BUTTON_UNPRESSED,
1195 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
1196 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
1197 GDI_EVENT_MASK, event_mask,
1198 GDI_CALLBACK_ACTION, HandleCounterButtons,
1202 Error(ERR_EXIT, "cannot create gadget");
1204 level_editor_gadget[id] = gi;
1205 xpos += gi->width + ED_GADGET_DISTANCE; /* xpos of text count button */
1209 id = counterbutton_info[i].gadget_id_text;
1210 event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
1212 gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
1213 gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
1215 gi = CreateGadget(GDI_CUSTOM_ID, id,
1216 GDI_INFO_TEXT, "enter counter value",
1219 GDI_TYPE, GD_TYPE_TEXTINPUT_NUMERIC,
1220 GDI_NUMBER_VALUE, 0,
1221 GDI_NUMBER_MIN, counterbutton_info[i].min_value,
1222 GDI_NUMBER_MAX, counterbutton_info[i].max_value,
1224 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
1225 GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
1226 GDI_DESIGN_BORDER, ED_BORDER_SIZE,
1227 GDI_EVENT_MASK, event_mask,
1228 GDI_CALLBACK_ACTION, HandleCounterButtons,
1232 Error(ERR_EXIT, "cannot create gadget");
1234 level_editor_gadget[id] = gi;
1235 xpos += gi->width + ED_GADGET_DISTANCE; /* xpos of up count button */
1241 static void CreateDrawingAreas()
1243 struct GadgetInfo *gi;
1244 unsigned long event_mask;
1249 GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
1250 GD_EVENT_OFF_BORDERS;
1252 /* one for the level drawing area ... */
1253 id = GADGET_ID_DRAWING_LEVEL;
1254 gi = CreateGadget(GDI_CUSTOM_ID, id,
1257 GDI_TYPE, GD_TYPE_DRAWING_AREA,
1258 GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
1259 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1260 GDI_EVENT_MASK, event_mask,
1261 GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1262 GDI_CALLBACK_ACTION, HandleDrawingAreas,
1266 Error(ERR_EXIT, "cannot create gadget");
1268 level_editor_gadget[id] = gi;
1270 /* ... up to eight areas for element content ... */
1271 for (i=0; i<MAX_ELEM_CONTENT; i++)
1273 int gx = SX + ED_AREA_ELEM_CONTENT_XPOS + 5 * (i % 4) * MINI_TILEX;
1274 int gy = SX + ED_AREA_ELEM_CONTENT_YPOS + 6 * (i / 4) * MINI_TILEY;
1276 id = GADGET_ID_ELEM_CONTENT_0 + i;
1277 gi = CreateGadget(GDI_CUSTOM_ID, id,
1280 GDI_WIDTH, 3 * MINI_TILEX,
1281 GDI_HEIGHT, 3 * MINI_TILEY,
1282 GDI_TYPE, GD_TYPE_DRAWING_AREA,
1283 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1284 GDI_EVENT_MASK, event_mask,
1285 GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1286 GDI_CALLBACK_ACTION, HandleDrawingAreas,
1290 Error(ERR_EXIT, "cannot create gadget");
1292 level_editor_gadget[id] = gi;
1295 /* ... and one for the amoeba content */
1296 id = GADGET_ID_AMOEBA_CONTENT;
1297 gi = CreateGadget(GDI_CUSTOM_ID, id,
1298 GDI_X, SX + ED_AREA_ELEM_CONTENT_XPOS,
1299 GDI_Y, SY + ED_AREA_ELEM_CONTENT_YPOS,
1300 GDI_WIDTH, MINI_TILEX,
1301 GDI_HEIGHT, MINI_TILEY,
1302 GDI_TYPE, GD_TYPE_DRAWING_AREA,
1303 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1304 GDI_EVENT_MASK, event_mask,
1305 GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1306 GDI_CALLBACK_ACTION, HandleDrawingAreas,
1310 Error(ERR_EXIT, "cannot create gadget");
1312 level_editor_gadget[id] = gi;
1315 static void CreateTextInputGadgets()
1319 for (i=0; i<ED_NUM_TEXTINPUT; i++)
1321 Pixmap gd_pixmap = pix[PIX_DOOR];
1323 struct GadgetInfo *gi;
1324 unsigned long event_mask;
1325 char infotext[1024];
1326 int id = GADGET_ID_LEVEL_NAME + i;
1328 event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
1330 gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
1331 gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
1333 sprintf(infotext, "Enter %s", textinput_info[i].infotext);
1334 infotext[MAX_INFOTEXT_LEN] = '\0';
1336 gi = CreateGadget(GDI_CUSTOM_ID, id,
1337 GDI_INFO_TEXT, infotext,
1338 GDI_X, SX + textinput_info[i].x,
1339 GDI_Y, SY + textinput_info[i].y,
1340 GDI_TYPE, GD_TYPE_TEXTINPUT_ALPHANUMERIC,
1341 GDI_TEXT_VALUE, textinput_info[i].value,
1343 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
1344 GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
1345 GDI_DESIGN_BORDER, ED_BORDER_SIZE,
1346 GDI_EVENT_MASK, event_mask,
1347 GDI_CALLBACK_ACTION, HandleTextInputGadgets,
1351 Error(ERR_EXIT, "cannot create gadget");
1353 level_editor_gadget[id] = gi;
1357 static void CreateScrollbarGadgets()
1361 for (i=0; i<ED_NUM_SCROLLBARS; i++)
1363 int id = scrollbar_info[i].gadget_id;
1364 Pixmap gd_pixmap = pix[PIX_DOOR];
1365 int gd_x1, gd_x2, gd_y1, gd_y2;
1366 struct GadgetInfo *gi;
1367 int items_max, items_visible, item_position;
1368 unsigned long event_mask;
1370 if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1372 items_max = MAX(lev_fieldx + 2, ed_fieldx);
1373 items_visible = ed_fieldx;
1378 items_max = MAX(lev_fieldy + 2, ed_fieldy);
1379 items_visible = ed_fieldy;
1383 event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
1385 gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].xpos;
1386 gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
1387 gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1388 gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1390 gi = CreateGadget(GDI_CUSTOM_ID, id,
1391 GDI_INFO_TEXT, scrollbar_info[i].infotext,
1392 GDI_X, SX + scrollbar_info[i].x,
1393 GDI_Y, SY + scrollbar_info[i].y,
1394 GDI_WIDTH, scrollbar_info[i].width,
1395 GDI_HEIGHT, scrollbar_info[i].height,
1396 GDI_TYPE, scrollbar_info[i].type,
1397 GDI_SCROLLBAR_ITEMS_MAX, items_max,
1398 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1399 GDI_SCROLLBAR_ITEM_POSITION, item_position,
1400 GDI_STATE, GD_BUTTON_UNPRESSED,
1401 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1402 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1403 GDI_DESIGN_BORDER, ED_BORDER_SIZE,
1404 GDI_EVENT_MASK, event_mask,
1405 GDI_CALLBACK_ACTION, HandleControlButtons,
1409 Error(ERR_EXIT, "cannot create gadget");
1411 level_editor_gadget[id] = gi;
1415 void CreateLevelEditorGadgets()
1417 CreateControlButtons();
1418 CreateCounterButtons();
1419 CreateDrawingAreas();
1420 CreateTextInputGadgets();
1421 CreateScrollbarGadgets();
1424 static void MapControlButtons()
1428 for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
1429 MapGadget(level_editor_gadget[i]);
1430 for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
1431 MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
1434 static void MapCounterButtons(int id)
1436 MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
1437 MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
1438 MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
1441 static void MapDrawingArea(int id)
1443 MapGadget(level_editor_gadget[id]);
1446 static void MapTextInputGadget(int id)
1448 MapGadget(level_editor_gadget[textinput_info[id].gadget_id]);
1451 static void MapMainDrawingArea()
1453 boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
1454 boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
1457 for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
1459 if (((i == ED_SCROLLBUTTON_AREA_LEFT || i == ED_SCROLLBUTTON_AREA_RIGHT) &&
1460 no_horizontal_scrollbar) ||
1461 ((i == ED_SCROLLBUTTON_AREA_UP || i == ED_SCROLLBUTTON_AREA_DOWN) &&
1462 no_vertical_scrollbar))
1465 MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
1468 for (i=0; i<ED_NUM_SCROLLBARS; i++)
1470 if ((i == ED_SCROLLBAR_HORIZONTAL && no_horizontal_scrollbar) ||
1471 (i == ED_SCROLLBAR_VERTICAL && no_vertical_scrollbar))
1474 MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
1477 MapDrawingArea(GADGET_ID_DRAWING_LEVEL);
1480 static void UnmapDrawingArea(int id)
1482 UnmapGadget(level_editor_gadget[id]);
1485 void UnmapLevelEditorWindowGadgets()
1489 for (i=0; i<NUM_EDITOR_GADGETS; i++)
1490 if (level_editor_gadget[i]->x < DX)
1491 UnmapGadget(level_editor_gadget[i]);
1494 void UnmapLevelEditorGadgets()
1498 for (i=0; i<NUM_EDITOR_GADGETS; i++)
1499 UnmapGadget(level_editor_gadget[i]);
1504 int i, x, y, graphic;
1506 edit_mode = ED_MODE_DRAWING;
1508 CloseDoor(DOOR_CLOSE_ALL);
1510 OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
1512 if (level_editor_test_game)
1514 for(x=0; x<lev_fieldx; x++)
1515 for(y=0; y<lev_fieldy; y++)
1516 Feld[x][y] = Ur[x][y];
1518 for(x=0; x<lev_fieldx; x++)
1519 for(y=0; y<lev_fieldy; y++)
1520 Ur[x][y] = FieldBackup[x][y];
1522 level_editor_test_game = FALSE;
1528 undo_buffer_position = -1;
1529 undo_buffer_steps = -1;
1530 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
1534 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
1538 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1539 DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY1,
1541 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1542 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1543 DOOR_GFX_PAGEX6+ED_BUTTON_ELEM_XPOS,
1544 DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS,
1545 4*ED_BUTTON_ELEM_XSIZE,5*ED_BUTTON_ELEM_YSIZE,
1546 DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS,
1547 DOOR_GFX_PAGEY1+ED_BUTTON_EUP_Y2POS);
1549 for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1551 if (i < elements_in_list)
1552 graphic = el2gfx(editor_element[i + element_shift]);
1554 graphic = GFX_LEERRAUM;
1556 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1557 DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS+3 +
1558 (i%MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
1559 DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS+3 +
1560 (i/MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
1564 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1565 DOOR_GFX_PAGEX1+ED_WIN_MB_LEFT_XPOS,
1566 DOOR_GFX_PAGEY1+ED_WIN_MB_LEFT_YPOS,
1567 el2gfx(new_element1));
1568 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1569 DOOR_GFX_PAGEX1+ED_WIN_MB_MIDDLE_XPOS,
1570 DOOR_GFX_PAGEY1+ED_WIN_MB_MIDDLE_YPOS,
1571 el2gfx(new_element2));
1572 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1573 DOOR_GFX_PAGEX1+ED_WIN_MB_RIGHT_XPOS,
1574 DOOR_GFX_PAGEY1+ED_WIN_MB_RIGHT_YPOS,
1575 el2gfx(new_element3));
1576 DrawTextExt(pix[PIX_DB_DOOR],gc,
1577 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS,
1578 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1579 int2str(level_nr,2),FS_SMALL,FC_SPECIAL1);
1580 XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1581 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+3,
1582 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1584 DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS,
1585 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1586 XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1587 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+14,
1588 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1590 DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS+9,
1591 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1593 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1594 DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1596 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1598 /* draw bigger door */
1599 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1604 /* draw new control window */
1605 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1606 DOOR_GFX_PAGEX8, 236,
1610 redraw_mask |= REDRAW_ALL;
1612 OpenDoor(DOOR_OPEN_1);
1614 strcpy(level_editor_gadget[GADGET_ID_LEVEL_NAME]->text.value, level.name);
1616 MapControlButtons();
1619 MapMainDrawingArea();
1622 DrawDrawingWindow();
1626 OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
1634 static void DrawControlWindow()
1639 UnmapLevelEditorWindowGadgets();
1641 /* Inhalt der Mampfer */
1642 DrawText(ED_COUNT_GADGET_XPOS+1,SY+6,
1643 "Contents of a smashed cruncher:",FS_SMALL,FC_YELLOW);
1644 for(i=0;i<4;i++) for(y=0;y<4;y++) for(x=0;x<4;x++)
1646 DrawMiniElement(1+5*i+x,2+y,EL_ERDREICH);
1647 XFillRectangle(display,drawto,gc,
1648 SX+(1+5*i)*MINI_TILEX+MINI_TILEX/2-1,
1649 SY+(2)*MINI_TILEY+MINI_TILEY/2-1,
1650 3*MINI_TILEX+2,3*MINI_TILEY+2);
1652 XCopyArea(display,drawto,drawto,gc,
1653 SX+1*MINI_TILEX,SY+2*MINI_TILEY,
1654 4*5*MINI_TILEX,5*MINI_TILEY,
1655 SX+1*MINI_TILEX-MINI_TILEX/2,SY+2*MINI_TILEY-MINI_TILEY/2);
1658 for(y=0;y<3;y++) for(x=0;x<3;x++)
1659 DrawMiniElement(1+5*i+x,2+y,level.mampfer_inhalt[i][x][y]);
1661 DrawText(SX+MINI_TILEX+(5*i+1)*MINI_TILEX+1,
1662 SY+2*MINI_TILEY+(4)*MINI_TILEY-4,
1663 int2str(i+1,1),FS_SMALL,FC_YELLOW);
1666 /* Inhalt der Amöbe */
1667 for(y=0;y<2;y++) for(x=0;x<2;x++)
1669 DrawMiniElement(29+x,26+y,EL_ERDREICH);
1670 XFillRectangle(display,drawto,gc,
1671 SX+29*MINI_TILEX+MINI_TILEX/2-1,
1672 SY+26*MINI_TILEY+MINI_TILEY/2-1,
1673 MINI_TILEX+2,MINI_TILEY+2);
1675 XCopyArea(display,drawto,drawto,gc,
1676 SX+29*MINI_TILEX,SY+26*MINI_TILEY,
1677 3*MINI_TILEX,3*MINI_TILEY,
1678 SX+29*MINI_TILEX-MINI_TILEX/2,SY+26*MINI_TILEY-MINI_TILEY/2);
1679 DrawMiniElement(29,26,level.amoebe_inhalt);
1681 for(i=0;i<11+3+2;i++)
1683 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1684 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1685 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1686 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1687 ED_COUNT_GADGET_XPOS,
1688 ED_COUNT_GADGET_YPOS+i*ED_COUNT_GADGET_YSIZE);
1691 DrawText(ED_COUNT_VALUE_XPOS,
1692 ED_COUNT_VALUE_YPOS+i*ED_COUNT_GADGET_YSIZE,
1693 int2str(level.score[i],3),FS_SMALL,FC_YELLOW);
1695 DrawText(ED_COUNT_VALUE_XPOS,
1696 ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1697 int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1699 DrawText(ED_COUNT_VALUE_XPOS,
1700 ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1701 int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1703 DrawText(ED_COUNT_VALUE_XPOS,
1704 ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1705 int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1707 DrawText(ED_COUNT_VALUE_XPOS,
1708 ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1709 int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1711 DrawText(ED_COUNT_VALUE_XPOS,
1712 ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1713 int2str(level.time,3),FS_SMALL,FC_YELLOW);
1716 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+0*ED_COUNT_TEXT_YSIZE,
1717 "Score for Emerald",FS_SMALL,FC_YELLOW);
1718 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+1*ED_COUNT_TEXT_YSIZE,
1719 "Score for Diamond",FS_SMALL,FC_YELLOW);
1720 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+2*ED_COUNT_TEXT_YSIZE,
1721 "Score for smashing a Bug",FS_SMALL,FC_YELLOW);
1722 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+3*ED_COUNT_TEXT_YSIZE,
1723 "Score for smashing a Spaceship",FS_SMALL,FC_YELLOW);
1724 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+4*ED_COUNT_TEXT_YSIZE,
1725 "Score for smashing a Cruncher",FS_SMALL,FC_YELLOW);
1726 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+5*ED_COUNT_TEXT_YSIZE,
1727 "Score for smashing an Alien",FS_SMALL,FC_YELLOW);
1728 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+6*ED_COUNT_TEXT_YSIZE,
1729 "Score for smashing a Pacman",FS_SMALL,FC_YELLOW);
1730 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+7*ED_COUNT_TEXT_YSIZE,
1731 "Score for cracking a nut",FS_SMALL,FC_YELLOW);
1732 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+8*ED_COUNT_TEXT_YSIZE,
1733 "Score for dynamite",FS_SMALL,FC_YELLOW);
1734 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+9*ED_COUNT_TEXT_YSIZE,
1735 "Score for key",FS_SMALL,FC_YELLOW);
1736 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+10*ED_COUNT_TEXT_YSIZE,
1737 "Score for each 10 seconds left",FS_SMALL,FC_YELLOW);
1738 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+11*ED_COUNT_TEXT_YSIZE,
1739 "Speed of the amoeba / Content",FS_SMALL,FC_YELLOW);
1740 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+12*ED_COUNT_TEXT_YSIZE,
1741 "Time for magic wall",FS_SMALL,FC_YELLOW);
1742 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+13*ED_COUNT_TEXT_YSIZE,
1743 "Time for wheel",FS_SMALL,FC_YELLOW);
1744 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+14*ED_COUNT_TEXT_YSIZE,
1745 "Emeralds needed in this level",FS_SMALL,FC_YELLOW);
1746 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+15*ED_COUNT_TEXT_YSIZE,
1747 "Time available for this level",FS_SMALL,FC_YELLOW);
1749 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1750 DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS,
1751 DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1752 ED_WIN_COUNT_XSIZE,ED_WIN_COUNT_YSIZE,
1753 ED_COUNT_GADGET_XPOS,
1754 ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1756 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1757 DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS+3+2*FONT2_XSIZE,
1758 DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1759 ED_WIN_COUNT_XSIZE-3-2*FONT2_XSIZE,ED_WIN_COUNT_YSIZE,
1760 ED_COUNT_GADGET_XPOS+3+i*FONT2_XSIZE,
1761 ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1762 DrawText(ED_COUNT_GADGET_XPOS+5,
1763 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1764 level.name,FS_SMALL,FC_YELLOW);
1765 DrawText(ED_COUNT_GADGET_XPOS+(30+3)*FONT2_XSIZE-5,
1766 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1767 "Title",FS_SMALL,FC_YELLOW);
1769 DrawText(ED_SIZE_GADGET_XPOS,ED_SIZE_GADGET_YPOS-18,
1770 "Playfield size:",FS_SMALL,FC_YELLOW);
1771 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1772 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1773 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1774 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1775 ED_SIZE_GADGET_XPOS,
1776 ED_SIZE_GADGET_YPOS+0*ED_COUNT_GADGET_YSIZE);
1777 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1778 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1779 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1780 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1781 ED_SIZE_GADGET_XPOS,
1782 ED_SIZE_GADGET_YPOS+1*ED_COUNT_GADGET_YSIZE);
1783 DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+0*ED_SIZE_TEXT_YSIZE,
1784 "Width",FS_SMALL,FC_YELLOW);
1785 DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+1*ED_SIZE_TEXT_YSIZE,
1786 "Height",FS_SMALL,FC_YELLOW);
1787 DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1788 int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1789 DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1790 int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1797 static void AdjustDrawingAreaGadgets()
1799 int ed_xsize = lev_fieldx + 2;
1800 int ed_ysize = lev_fieldy + 2;
1801 int max_ed_fieldx = MAX_ED_FIELDX;
1802 int max_ed_fieldy = MAX_ED_FIELDY;
1803 boolean horizontal_scrollbar_needed;
1804 boolean vertical_scrollbar_needed;
1805 int x, y, width, height;
1806 int xoffset, yoffset;
1808 /* check if we need any scrollbars */
1809 horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
1810 vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
1812 /* check if we have a smaller editor field because of scrollbars */
1813 if (horizontal_scrollbar_needed)
1814 max_ed_fieldy = MAX_ED_FIELDY - 1;
1815 if (vertical_scrollbar_needed)
1816 max_ed_fieldx = MAX_ED_FIELDX - 1;
1818 /* check again if we now need more scrollbars because of less space */
1819 horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
1820 vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
1822 /* check if editor field gets even smaller after adding new scrollbars */
1823 if (horizontal_scrollbar_needed)
1824 max_ed_fieldy = MAX_ED_FIELDY - 1;
1825 if (vertical_scrollbar_needed)
1826 max_ed_fieldx = MAX_ED_FIELDX - 1;
1828 ed_fieldx = (ed_xsize < MAX_ED_FIELDX ? ed_xsize : max_ed_fieldx);
1829 ed_fieldy = (ed_ysize < MAX_ED_FIELDY ? ed_ysize : max_ed_fieldy);
1831 ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
1832 GDI_WIDTH, ed_fieldx * MINI_TILEX,
1833 GDI_HEIGHT, ed_fieldy * MINI_TILEY,
1834 GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
1837 xoffset = (ed_fieldx == MAX_ED_FIELDX ? ED_SCROLLBUTTON_XSIZE : 0);
1838 yoffset = (ed_fieldy == MAX_ED_FIELDY ? ED_SCROLLBUTTON_YSIZE : 0);
1840 x = SX + scrollbutton_info[ED_SCROLLBUTTON_AREA_RIGHT].x + xoffset;
1841 y = SX + scrollbutton_info[ED_SCROLLBUTTON_AREA_DOWN].y + yoffset;
1843 ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END);
1844 ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END);
1846 width = scrollbar_info[ED_SCROLLBAR_HORIZONTAL].width + xoffset;
1847 height = scrollbar_info[ED_SCROLLBAR_VERTICAL].height + yoffset;
1849 ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
1851 GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
1853 ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
1855 GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
1859 static void AdjustLevelScrollPosition()
1861 if (level_xpos < -1)
1863 if (level_xpos > lev_fieldx - ed_fieldx + 1)
1864 level_xpos = lev_fieldx - ed_fieldx + 1;
1865 if (lev_fieldx < ed_fieldx - 2)
1868 if (level_ypos < -1)
1870 if (level_ypos > lev_fieldy - ed_fieldy + 1)
1871 level_ypos = lev_fieldy - ed_fieldy + 1;
1872 if (lev_fieldy < ed_fieldy - 2)
1876 static void AdjustEditorScrollbar(int id)
1878 struct GadgetInfo *gi = level_editor_gadget[id];
1879 int items_max, items_visible, item_position;
1881 if (id == GADGET_ID_SCROLL_HORIZONTAL)
1883 items_max = MAX(lev_fieldx + 2, ed_fieldx);
1884 items_visible = ed_fieldx;
1885 item_position = level_xpos + 1;
1889 items_max = MAX(lev_fieldy + 2, ed_fieldy);
1890 items_visible = ed_fieldy;
1891 item_position = level_ypos + 1;
1894 if (item_position > items_max - items_visible)
1895 item_position = items_max - items_visible;
1897 ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
1898 GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
1901 static void ModifyEditorTextInput(int textinput_id, char *new_text)
1903 int gadget_id = textinput_info[textinput_id].gadget_id;
1904 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1906 ModifyGadget(gi, GDI_TEXT_VALUE, new_text, GDI_END);
1909 static void ModifyEditorCounter(int counter_id, int new_value)
1911 int *counter_value = *counterbutton_info[counter_id].counter_value;
1912 int gadget_id = counterbutton_info[counter_id].gadget_id_text;
1913 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1915 ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
1917 if (counter_value != NULL)
1918 *counter_value = gi->text.number_value;
1921 static void PickDrawingElement(int button, int element)
1923 if (button < 1 || button > 3)
1928 new_element1 = element;
1929 DrawMiniGraphicExt(drawto, gc,
1930 DX + ED_WIN_MB_LEFT_XPOS,
1931 DY + ED_WIN_MB_LEFT_YPOS,
1932 el2gfx(new_element1));
1934 else if (button == 2)
1936 new_element2 = element;
1937 DrawMiniGraphicExt(drawto, gc,
1938 DX + ED_WIN_MB_MIDDLE_XPOS,
1939 DY + ED_WIN_MB_MIDDLE_YPOS,
1940 el2gfx(new_element2));
1944 new_element3 = element;
1945 DrawMiniGraphicExt(drawto, gc,
1946 DX + ED_WIN_MB_RIGHT_XPOS,
1947 DY + ED_WIN_MB_RIGHT_YPOS,
1948 el2gfx(new_element3));
1951 redraw_mask |= REDRAW_DOOR_1;
1954 static void DrawCounterValueField(int counter_id, int value)
1956 int x = SX + counterbutton_info[counter_id].x + ED_WIN_COUNT_XPOS;
1957 int y = SY + counterbutton_info[counter_id].y;
1959 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1960 DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS,
1961 DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS,
1962 ED_WIN_COUNT_XSIZE, ED_WIN_COUNT_YSIZE,
1965 DrawText(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
1966 int2str(value, 3), FS_SMALL, FC_YELLOW);
1969 static void DrawDrawingWindow()
1972 UnmapLevelEditorWindowGadgets();
1973 AdjustDrawingAreaGadgets();
1974 AdjustLevelScrollPosition();
1975 AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
1976 AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
1977 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
1978 MapMainDrawingArea();
1981 static void DrawLevelInfoWindow()
1983 char infotext[1024];
1984 int infotext_yoffset = MINI_TILEX + ED_GADGET_DISTANCE;
1988 UnmapLevelEditorWindowGadgets();
1990 DrawTextF(ED_LEVELINFO_XPOS, ED_LEVELINFO_YPOS, FC_YELLOW,
1991 "Level Information");
1993 gadget_level_xsize_value = &lev_fieldx;
1994 gadget_level_ysize_value = &lev_fieldy;
1995 gadget_level_random_value = &random_placement_num_objects;
1996 gadget_level_collect_value = &level.edelsteine;
1997 gadget_level_timelimit_value = &level.time;
1998 gadget_level_timescore_value = &level.score[10];
2000 /* draw counter gadgets for level info */
2001 for (i=ED_COUNTER_ID_LEVEL_XSIZE; i<=ED_COUNTER_ID_LEVEL_TIMESCORE; i++)
2003 x = counterbutton_info[i].x;
2004 y = counterbutton_info[i].y - infotext_yoffset;
2006 sprintf(infotext, "%s:", counterbutton_info[i].infotext);
2007 infotext[MAX_INFOTEXT_LEN] = '\0';
2009 DrawTextF(x, y, FC_YELLOW, infotext);
2010 ModifyEditorCounter(i, **counterbutton_info[i].counter_value);
2011 MapCounterButtons(i);
2014 /* draw text input gadgets for level info */
2015 for (i=ED_TEXTINPUT_ID_LEVEL_NAME; i<=ED_TEXTINPUT_ID_LEVEL_AUTHOR; i++)
2017 x = textinput_info[i].x;
2018 y = textinput_info[i].y - infotext_yoffset;
2020 sprintf(infotext, "%s:", textinput_info[i].infotext);
2021 infotext[MAX_INFOTEXT_LEN] = '\0';
2023 DrawTextF(x, y, FC_YELLOW, infotext);
2024 ModifyEditorTextInput(i, textinput_info[i].value);
2025 MapTextInputGadget(i);
2029 static void DrawElementContentAreas()
2031 int *num_areas = &MampferMax;
2032 int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
2033 int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
2034 int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
2035 int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
2038 for (i=0; i<MAX_ELEM_CONTENT; i++)
2041 ElementContent[i][x][y] = level.mampfer_inhalt[i][x][y];
2043 for (i=0; i<MAX_ELEM_CONTENT; i++)
2044 UnmapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
2046 /* display counter to choose number of element content areas */
2047 gadget_elem_content_value = num_areas;
2048 DrawCounterValueField(ED_COUNTER_ID_ELEM_CONTENT,*gadget_elem_content_value);
2049 x = counterbutton_info[ED_COUNTER_ID_ELEM_CONTENT].x + counter_xsize;
2050 y = counterbutton_info[ED_COUNTER_ID_ELEM_CONTENT].y;
2051 DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2052 FC_YELLOW, "number of content areas");
2053 ModifyEditorCounter(ED_COUNTER_ID_ELEM_CONTENT, *gadget_elem_content_value);
2054 MapCounterButtons(ED_COUNTER_ID_ELEM_CONTENT);
2056 /* delete content areas in case of reducing number of them */
2057 XFillRectangle(display, backbuffer, gc,
2058 SX, area_sy - MINI_TILEX,
2059 SXSIZE, 12 * MINI_TILEY);
2061 /* draw some decorative border for the objects */
2062 for (i=0; i<*num_areas; i++)
2066 DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2069 XFillRectangle(display, drawto, gc,
2070 area_sx + 5 * (i % 4) * MINI_TILEX + MINI_TILEX/2 - 1,
2071 area_sy + 6 * (i / 4) * MINI_TILEY + MINI_TILEY/2 - 1,
2072 3 * MINI_TILEX + 2, 3 * MINI_TILEY + 2);
2075 /* copy border to the right location */
2076 XCopyArea(display, drawto, drawto, gc,
2077 area_sx, area_sy, (5 * 4 + 1) * MINI_TILEX, 12 * MINI_TILEY,
2078 area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2080 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
2081 "Content", FS_SMALL, FC_YELLOW);
2082 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
2083 "when", FS_SMALL, FC_YELLOW);
2084 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
2085 "smashed", FS_SMALL, FC_YELLOW);
2087 for (i=0; i<*num_areas; i++)
2091 DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2092 ElementContent[i][x][y]);
2094 DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
2095 area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
2096 FC_YELLOW, "%d", i + 1);
2099 for (i=0; i<*num_areas; i++)
2100 MapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
2103 static void DrawAmoebaContentArea()
2105 int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
2106 int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
2107 int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
2108 int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
2111 ElementContent[0][0][0] = level.amoebe_inhalt;
2113 /* draw decorative border for the object */
2116 DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
2118 XFillRectangle(display, drawto, gc,
2119 area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
2120 MINI_TILEX + 2, MINI_TILEY + 2);
2122 /* copy border to the right location */
2123 XCopyArea(display, drawto, drawto, gc,
2124 area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
2125 area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2127 DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba",
2128 FS_SMALL, FC_YELLOW);
2130 DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
2132 MapDrawingArea(GADGET_ID_AMOEBA_CONTENT);
2135 #define TEXT_COLLECTING "Score for collecting"
2136 #define TEXT_SMASHING "Score for smashing"
2137 #define TEXT_CRACKING "Score for cracking"
2138 #define TEXT_SPEED "Speed of amoeba growth"
2139 #define TEXT_DURATION "Duration when activated"
2141 static void DrawPropertiesWindow()
2144 int num_elements_in_level;
2150 } elements_with_counter[] =
2152 { EL_EDELSTEIN, &level.score[0], TEXT_COLLECTING },
2153 { EL_EDELSTEIN_BD, &level.score[0], TEXT_COLLECTING },
2154 { EL_EDELSTEIN_GELB,&level.score[0], TEXT_COLLECTING },
2155 { EL_EDELSTEIN_ROT, &level.score[0], TEXT_COLLECTING },
2156 { EL_EDELSTEIN_LILA,&level.score[0], TEXT_COLLECTING },
2157 { EL_DIAMANT, &level.score[1], TEXT_COLLECTING },
2158 { EL_KAEFER_R, &level.score[2], TEXT_SMASHING },
2159 { EL_KAEFER_O, &level.score[2], TEXT_SMASHING },
2160 { EL_KAEFER_L, &level.score[2], TEXT_SMASHING },
2161 { EL_KAEFER_U, &level.score[2], TEXT_SMASHING },
2162 { EL_BUTTERFLY_R, &level.score[2], TEXT_SMASHING },
2163 { EL_BUTTERFLY_O, &level.score[2], TEXT_SMASHING },
2164 { EL_BUTTERFLY_L, &level.score[2], TEXT_SMASHING },
2165 { EL_BUTTERFLY_U, &level.score[2], TEXT_SMASHING },
2166 { EL_FLIEGER_R, &level.score[3], TEXT_SMASHING },
2167 { EL_FLIEGER_O, &level.score[3], TEXT_SMASHING },
2168 { EL_FLIEGER_L, &level.score[3], TEXT_SMASHING },
2169 { EL_FLIEGER_U, &level.score[3], TEXT_SMASHING },
2170 { EL_FIREFLY_R, &level.score[3], TEXT_SMASHING },
2171 { EL_FIREFLY_O, &level.score[3], TEXT_SMASHING },
2172 { EL_FIREFLY_L, &level.score[3], TEXT_SMASHING },
2173 { EL_FIREFLY_U, &level.score[3], TEXT_SMASHING },
2174 { EL_MAMPFER, &level.score[4], TEXT_SMASHING },
2175 { EL_MAMPFER2, &level.score[4], TEXT_SMASHING },
2176 { EL_ROBOT, &level.score[5], TEXT_SMASHING },
2177 { EL_PACMAN_R, &level.score[6], TEXT_SMASHING },
2178 { EL_PACMAN_O, &level.score[6], TEXT_SMASHING },
2179 { EL_PACMAN_L, &level.score[6], TEXT_SMASHING },
2180 { EL_PACMAN_U, &level.score[6], TEXT_SMASHING },
2181 { EL_KOKOSNUSS, &level.score[7], TEXT_CRACKING },
2182 { EL_DYNAMIT_AUS, &level.score[8], TEXT_COLLECTING },
2183 { EL_SCHLUESSEL1, &level.score[9], TEXT_COLLECTING },
2184 { EL_SCHLUESSEL2, &level.score[9], TEXT_COLLECTING },
2185 { EL_SCHLUESSEL3, &level.score[9], TEXT_COLLECTING },
2186 { EL_SCHLUESSEL4, &level.score[9], TEXT_COLLECTING },
2187 { EL_AMOEBE_NASS, &level.tempo_amoebe, TEXT_SPEED },
2188 { EL_AMOEBE_NORM, &level.tempo_amoebe, TEXT_SPEED },
2189 { EL_AMOEBE_VOLL, &level.tempo_amoebe, TEXT_SPEED },
2190 { EL_AMOEBE_BD, &level.tempo_amoebe, TEXT_SPEED },
2191 { EL_SIEB_INAKTIV, &level.dauer_sieb, TEXT_DURATION },
2192 { EL_ABLENK_AUS, &level.dauer_ablenk, TEXT_DURATION },
2197 UnmapLevelEditorWindowGadgets();
2199 /* draw some decorative border for the object */
2202 DrawMiniElement(2 + x , 2 + y, EL_ERDREICH);
2204 XFillRectangle(display, drawto, gc,
2205 SX + TILEX + MINI_TILEX/2 - 1,
2206 SY + TILEY + MINI_TILEY/2 - 1,
2207 TILEX + 2, TILEY + 2);
2209 /* copy border to the right location */
2210 XCopyArea(display, drawto, drawto, gc,
2211 SX + TILEX, SY + TILEY,
2212 2 * TILEX, 2 * TILEY,
2213 SX + TILEX - MINI_TILEX/2, SY + TILEY - MINI_TILEY/2);
2215 DrawGraphic(1, 1, el2gfx(properties_element));
2216 DrawText(SX + 3*TILEX, SY + 5*TILEY/4, "Element Properties",
2217 FS_SMALL, FC_YELLOW);
2219 num_elements_in_level = 0;
2220 for (y=0; y<lev_fieldy; y++)
2221 for (x=0; x<lev_fieldx; x++)
2222 if (Feld[x][y] == properties_element)
2223 num_elements_in_level++;
2225 DrawTextF(ED_PROPERTIES_XPOS, 5*TILEY, FC_YELLOW, "%d x contained in level",
2226 num_elements_in_level);
2228 /* check if there are elements where a score can be chosen for */
2229 for (i=0; elements_with_counter[i].element != -1; i++)
2231 if (elements_with_counter[i].element == properties_element)
2233 int x = counterbutton_info[ED_COUNTER_ID_ELEM_SCORE].x + counter_xsize;
2234 int y = counterbutton_info[ED_COUNTER_ID_ELEM_SCORE].y;
2236 gadget_elem_score_value = elements_with_counter[i].counter_value;
2239 DrawCounterValueField(ED_COUNTER_ID_SCORE, *gadget_score_value);
2242 DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2243 FC_YELLOW, elements_with_counter[i].text);
2244 ModifyEditorCounter(ED_COUNTER_ID_ELEM_SCORE, *gadget_elem_score_value);
2245 MapCounterButtons(ED_COUNTER_ID_ELEM_SCORE);
2250 if (HAS_CONTENT(properties_element))
2252 if (IS_AMOEBOID(properties_element))
2253 DrawAmoebaContentArea();
2255 DrawElementContentAreas();
2259 static void swap_numbers(int *i1, int *i2)
2267 static void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
2279 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
2281 int lx = sx + level_xpos;
2282 int ly = sy + level_ypos;
2284 DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element));
2287 Feld[lx][ly] = element;
2290 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
2291 int element, boolean change_level)
2293 if (from_y == to_y) /* horizontal line */
2299 swap_numbers(&from_x, &to_x);
2301 for (x=from_x; x<=to_x; x++)
2302 DrawLineElement(x, y, element, change_level);
2304 else if (from_x == to_x) /* vertical line */
2310 swap_numbers(&from_y, &to_y);
2312 for (y=from_y; y<=to_y; y++)
2313 DrawLineElement(x, y, element, change_level);
2315 else /* diagonal line */
2317 int len_x = ABS(to_x - from_x);
2318 int len_y = ABS(to_y - from_y);
2321 if (len_y < len_x) /* a < 1 */
2323 float a = (float)len_y / (float)len_x;
2326 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2328 for (x=0; x<=len_x; x++)
2330 y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1);
2331 DrawLineElement(from_x + x, from_y + y, element, change_level);
2336 float a = (float)len_x / (float)len_y;
2339 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2341 for (y=0; y<=len_y; y++)
2343 x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1);
2344 DrawLineElement(from_x + x, from_y + y, element, change_level);
2350 static void DrawRectangle(int from_x, int from_y, int to_x, int to_y,
2351 int element, boolean change_level)
2353 DrawLine(from_x, from_y, from_x, to_y, element, change_level);
2354 DrawLine(from_x, to_y, to_x, to_y, element, change_level);
2355 DrawLine(to_x, to_y, to_x, from_y, element, change_level);
2356 DrawLine(to_x, from_y, from_x, from_y, element, change_level);
2359 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
2360 int element, boolean change_level)
2365 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2367 for (y=from_y; y<=to_y; y++)
2368 DrawLine(from_x, y, to_x, y, element, change_level);
2371 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
2372 int element, boolean change_level)
2374 int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
2375 int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
2376 int len_x = ABS(to_x - from_x);
2377 int len_y = ABS(to_y - from_y);
2380 radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
2382 /* not optimal (some points get drawn twice) but simple,
2383 and fast enough for the few points we are drawing */
2385 for (x=0; x<=radius; x++)
2389 y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
2391 sx = from_x + x * (from_x < to_x2 ? +1 : -1);
2392 sy = from_y + y * (from_y < to_y2 ? +1 : -1);
2393 lx = sx + level_xpos;
2394 ly = sy + level_ypos;
2396 if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
2397 DrawLineElement(sx, sy, element, change_level);
2400 for (y=0; y<=radius; y++)
2404 x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
2406 sx = from_x + x * (from_x < to_x2 ? +1 : -1);
2407 sy = from_y + y * (from_y < to_y2 ? +1 : -1);
2408 lx = sx + level_xpos;
2409 ly = sy + level_ypos;
2411 if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
2412 DrawLineElement(sx, sy, element, change_level);
2416 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
2417 int element, boolean change_level)
2419 int to_x2 = to_x + (to_x < from_x ? -1 : +1);
2420 int to_y2 = to_y + (to_y > from_y ? +1 : -1);
2422 DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
2426 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
2427 int element, boolean change_level)
2429 int to_x2 = to_x + (to_x < from_x ? -1 : +1);
2430 int to_y2 = to_y + (to_y > from_y ? +1 : -1);
2431 int mirror_to_x2 = from_x - (to_x2 - from_x);
2432 int mirror_to_y2 = from_y - (to_y2 - from_y);
2434 DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
2435 DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
2436 DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
2437 DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
2441 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
2443 int from_sx, from_sy;
2447 swap_numbers(&from_x, &to_x);
2450 swap_numbers(&from_y, &to_y);
2452 from_sx = SX + from_x * MINI_TILEX;
2453 from_sy = SY + from_y * MINI_TILEY;
2454 to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
2455 to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
2457 XSetForeground(display, gc, WhitePixel(display, screen));
2459 XDrawLine(display, drawto, gc, from_sx, from_sy, to_sx, from_sy);
2460 XDrawLine(display, drawto, gc, to_sx, from_sy, to_sx, to_sy);
2461 XDrawLine(display, drawto, gc, to_sx, to_sy, from_sx, to_sy);
2462 XDrawLine(display, drawto, gc, from_sx, to_sy, from_sx, from_sy);
2464 XSetForeground(display, gc, BlackPixel(display, screen));
2466 if (from_x == to_x && from_y == to_y)
2467 MarkTileDirty(from_x/2, from_y/2);
2469 redraw_mask |= REDRAW_FIELD;
2472 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
2473 int element, boolean change_level)
2475 if (element == -1 || change_level)
2476 DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE);
2478 DrawAreaBorder(from_x, from_y, to_x, to_y);
2481 /* values for CopyBrushExt() */
2482 #define CB_AREA_TO_BRUSH 0
2483 #define CB_BRUSH_TO_CURSOR 1
2484 #define CB_BRUSH_TO_LEVEL 2
2485 #define CB_DELETE_OLD_CURSOR 3
2487 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
2488 int button, int mode)
2490 static short brush_buffer[MAX_ED_FIELDX][MAX_ED_FIELDY];
2491 static int brush_width, brush_height;
2492 static int last_cursor_x = -1, last_cursor_y = -1;
2493 static boolean delete_old_brush;
2497 if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
2500 new_element = (button == 1 ? new_element1 :
2501 button == 2 ? new_element2 :
2502 button == 3 ? new_element3 : 0);
2504 if (mode == CB_AREA_TO_BRUSH)
2506 int from_lx, from_ly;
2509 swap_numbers(&from_x, &to_x);
2512 swap_numbers(&from_y, &to_y);
2514 brush_width = to_x - from_x + 1;
2515 brush_height = to_y - from_y + 1;
2517 from_lx = from_x + level_xpos;
2518 from_ly = from_y + level_ypos;
2520 for (y=0; y<brush_height; y++)
2522 for (x=0; x<brush_width; x++)
2524 brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
2527 DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
2532 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2534 delete_old_brush = FALSE;
2536 else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
2537 mode == CB_BRUSH_TO_LEVEL)
2539 int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
2540 int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
2541 int cursor_from_x = cursor_x - brush_width / 2;
2542 int cursor_from_y = cursor_y - brush_height / 2;
2543 int border_from_x = cursor_x, border_from_y = cursor_y;
2544 int border_to_x = cursor_x, border_to_y = cursor_y;
2546 if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
2547 CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2549 if (!IN_ED_FIELD(cursor_x, cursor_y) ||
2550 !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
2552 delete_old_brush = FALSE;
2556 for (y=0; y<brush_height; y++)
2558 for (x=0; x<brush_width; x++)
2560 int sx = cursor_from_x + x;
2561 int sy = cursor_from_y + y;
2562 int lx = sx + level_xpos;
2563 int ly = sy + level_ypos;
2564 boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
2565 int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
2566 mode == CB_BRUSH_TO_CURSOR || button == 1 ?
2567 brush_buffer[x][y] : new_element);
2569 if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
2571 if (sx < border_from_x)
2573 else if (sx > border_to_x)
2575 if (sy < border_from_y)
2577 else if (sy > border_to_y)
2580 DrawLineElement(sx, sy, element, change_level);
2586 printf("%d, %d - %d, %d in level and screen\n",
2587 border_from_x, border_from_y, border_to_x, border_to_y);
2590 if (mode != CB_DELETE_OLD_CURSOR)
2591 DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
2594 if (mode == CB_BRUSH_TO_LEVEL)
2595 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2598 last_cursor_x = cursor_x;
2599 last_cursor_y = cursor_y;
2600 delete_old_brush = TRUE;
2604 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
2607 CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
2610 static void CopyBrushToLevel(int x, int y, int button)
2612 CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
2615 static void CopyBrushToCursor(int x, int y)
2617 CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
2620 static void DeleteBrushFromCursor()
2622 CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2625 static void FloodFill(int from_x, int from_y, int fill_element)
2629 static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
2630 static int safety = 0;
2632 /* check if starting field still has the desired content */
2633 if (Feld[from_x][from_y] == fill_element)
2638 if (safety > lev_fieldx*lev_fieldy)
2639 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
2641 old_element = Feld[from_x][from_y];
2642 Feld[from_x][from_y] = fill_element;
2646 x = from_x + check[i][0];
2647 y = from_y + check[i][1];
2649 if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element)
2650 FloodFill(x, y, fill_element);
2656 /* values for DrawLevelText() modes */
2658 #define TEXT_SETCURSOR 1
2659 #define TEXT_WRITECHAR 2
2660 #define TEXT_BACKSPACE 3
2661 #define TEXT_NEWLINE 4
2664 static void DrawLevelText(int sx, int sy, char letter, int mode)
2666 static short delete_buffer[MAX_LEV_FIELDX];
2667 static int start_sx, start_sy;
2668 static int last_sx, last_sy;
2669 static boolean typing = FALSE;
2670 int letter_element = EL_CHAR_ASCII0 + letter;
2673 /* map lower case letters to upper case and convert special characters */
2674 if (letter >= 'a' && letter <= 'z')
2675 letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
2676 else if (letter == 'ä' || letter == 'Ä')
2677 letter_element = EL_CHAR_AE;
2678 else if (letter == 'ö' || letter == 'Ö')
2679 letter_element = EL_CHAR_OE;
2680 else if (letter == 'ü' || letter == 'Ü')
2681 letter_element = EL_CHAR_UE;
2682 else if (letter == '^')
2683 letter_element = EL_CHAR_COPY;
2685 letter_element = EL_CHAR_ASCII0 + letter;
2687 if (mode != TEXT_INIT)
2692 if (mode != TEXT_SETCURSOR)
2698 lx = last_sx + level_xpos;
2699 ly = last_sy + level_ypos;
2706 DrawLevelText(0, 0, 0, TEXT_END);
2709 start_sx = last_sx = sx;
2710 start_sy = last_sy = sy;
2711 DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
2714 case TEXT_SETCURSOR:
2715 DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
2716 DrawAreaBorder(sx, sy, sx, sy);
2721 case TEXT_WRITECHAR:
2722 if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
2724 delete_buffer[sx - start_sx] = Feld[lx][ly];
2725 Feld[lx][ly] = letter_element;
2727 if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
2728 DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
2729 else if (sy + 1 < ed_fieldy && ly + 1 < lev_fieldy)
2730 DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2732 DrawLevelText(0, 0, 0, TEXT_END);
2736 case TEXT_BACKSPACE:
2739 Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
2740 DrawMiniElement(sx - 1, sy, new_element3);
2741 DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
2746 if (sy + 1 < ed_fieldy - 1 && ly + 1 < lev_fieldy - 1)
2747 DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2749 DrawLevelText(0, 0, 0, TEXT_END);
2753 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2754 DrawMiniElement(sx, sy, Feld[lx][ly]);
2763 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
2764 int element, boolean change_level)
2766 int lx = sx + level_xpos;
2767 int ly = sy + level_ypos;
2770 DrawMiniElement(sx, sy, Feld[lx][ly]);
2772 DrawAreaBorder(sx, sy, sx, sy);
2775 static void CopyLevelToUndoBuffer(int mode)
2777 static boolean accumulated_undo = FALSE;
2778 boolean new_undo_buffer_position = TRUE;
2783 case UNDO_IMMEDIATE:
2784 accumulated_undo = FALSE;
2787 case UNDO_ACCUMULATE:
2788 if (accumulated_undo)
2789 new_undo_buffer_position = FALSE;
2790 accumulated_undo = TRUE;
2797 if (new_undo_buffer_position)
2799 /* new position in undo buffer ring */
2800 undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
2802 if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
2803 undo_buffer_steps++;
2806 for(x=0; x<lev_fieldx; x++)
2807 for(y=0; y<lev_fieldy; y++)
2808 UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
2811 printf("level saved to undo buffer\n");
2816 static void RandomPlacement(int button)
2821 new_element = (button == 1 ? new_element1 :
2822 button == 2 ? new_element2 :
2823 button == 3 ? new_element3 : 0);
2825 if (random_placement_method == RANDOM_USE_PERCENTAGE)
2827 for(x=0; x<lev_fieldx; x++)
2828 for(y=0; y<lev_fieldy; y++)
2829 if (RND(100) < random_placement_percentage)
2830 Feld[x][y] = new_element;
2834 int elements_left = random_placement_num_objects;
2836 while (elements_left > 0)
2838 x = RND(lev_fieldx);
2839 y = RND(lev_fieldy);
2841 if (Feld[x][y] != new_element)
2843 Feld[x][y] = new_element;
2849 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
2850 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2853 void WrapLevel(int dx, int dy)
2855 int wrap_dx = lev_fieldx - dx;
2856 int wrap_dy = lev_fieldy - dy;
2859 for(x=0; x<lev_fieldx; x++)
2860 for(y=0; y<lev_fieldy; y++)
2861 FieldBackup[x][y] = Feld[x][y];
2863 for(x=0; x<lev_fieldx; x++)
2864 for(y=0; y<lev_fieldy; y++)
2866 FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
2868 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
2869 CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
2872 static void HandleDrawingAreas(struct GadgetInfo *gi)
2874 static boolean started_inside_drawing_area = FALSE;
2875 int id = gi->custom_id;
2876 boolean button_press_event;
2877 boolean button_release_event;
2878 boolean inside_drawing_area = !gi->event.off_borders;
2879 boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
2881 int button = gi->event.button;
2882 int sx = gi->event.x, sy = gi->event.y;
2883 int min_sx = 0, min_sy = 0;
2884 int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
2886 int min_lx = 0, min_ly = 0;
2887 int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
2890 /* handle info callback for each invocation of action callback */
2891 gi->callback_info(gi);
2894 if (edit_mode != ED_MODE_DRAWING)
2898 button_press_event = (gi->event.type == GD_EVENT_PRESSED);
2899 button_release_event = (gi->event.type == GD_EVENT_RELEASED);
2901 /* make sure to stay inside drawing area boundaries */
2902 sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
2903 sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
2907 /* get positions inside level field */
2908 lx = sx + level_xpos;
2909 ly = sy + level_ypos;
2911 if (!IN_LEV_FIELD(lx, ly))
2912 inside_drawing_area = FALSE;
2914 /* make sure to stay inside level field boundaries */
2915 lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
2916 ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
2918 /* correct drawing area positions accordingly */
2919 sx = lx - level_xpos;
2920 sy = ly - level_ypos;
2923 if (button_press_event)
2924 started_inside_drawing_area = inside_drawing_area;
2926 if (!started_inside_drawing_area)
2929 if (!button && !button_release_event)
2932 new_element = (button == 1 ? new_element1 :
2933 button == 2 ? new_element2 :
2934 button == 3 ? new_element3 : 0);
2938 if (button_release_event)
2943 if (!draw_level && drawing_function != GADGET_ID_SINGLE_ITEMS)
2946 switch (drawing_function)
2948 case GADGET_ID_SINGLE_ITEMS:
2951 if (button_release_event)
2953 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2955 if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
2956 !inside_drawing_area)
2957 DeleteBrushFromCursor();
2963 if (draw_with_brush)
2965 if (!button_release_event)
2966 CopyBrushToLevel(sx, sy, button);
2968 else if (new_element != Feld[lx][ly])
2970 if (new_element == EL_SPIELFIGUR)
2972 /* remove player at old position */
2973 for(y=0; y<lev_fieldy; y++)
2975 for(x=0; x<lev_fieldx; x++)
2977 if (Feld[x][y] == EL_SPIELFIGUR || Feld[x][y] == EL_SPIELER1)
2979 Feld[x][y] = EL_LEERRAUM;
2980 if (x - level_xpos >= 0 && x - level_xpos < ed_fieldx &&
2981 y - level_ypos >= 0 && y - level_ypos < ed_fieldy)
2982 DrawMiniElement(x - level_xpos, y - level_ypos,
2989 Feld[lx][ly] = new_element;
2990 DrawMiniElement(sx, sy, new_element);
2995 DrawMiniGraphicExt(drawto, gc,
2996 gi->x + sx * MINI_TILEX,
2997 gi->y + sy * MINI_TILEY,
2998 el2gfx(new_element));
2999 DrawMiniGraphicExt(window, gc,
3000 gi->x + sx * MINI_TILEX,
3001 gi->y + sy * MINI_TILEY,
3002 el2gfx(new_element));
3004 if (id == GADGET_ID_AMOEBA_CONTENT)
3005 level.amoebe_inhalt = new_element;
3006 else if (id >= GADGET_ID_ELEM_CONTENT_0 &&
3007 id <= GADGET_ID_ELEM_CONTENT_7)
3008 level.mampfer_inhalt[id - GADGET_ID_ELEM_CONTENT_0][sx][sy] =
3013 case GADGET_ID_CONNECTED_ITEMS:
3015 static int last_sx = -1;
3016 static int last_sy = -1;
3018 if (button_release_event)
3019 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3023 if (!button_press_event)
3024 DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
3032 case GADGET_ID_LINE:
3034 case GADGET_ID_RECTANGLE:
3035 case GADGET_ID_FILLED_BOX:
3036 case GADGET_ID_GRAB_BRUSH:
3037 case GADGET_ID_TEXT:
3039 static int last_sx = -1;
3040 static int last_sy = -1;
3041 static int start_sx = -1;
3042 static int start_sy = -1;
3043 void (*draw_func)(int, int, int, int, int, boolean);
3045 if (drawing_function == GADGET_ID_LINE)
3046 draw_func = DrawLine;
3047 else if (drawing_function == GADGET_ID_ARC)
3048 draw_func = DrawArc;
3049 else if (drawing_function == GADGET_ID_RECTANGLE)
3050 draw_func = DrawRectangle;
3051 else if (drawing_function == GADGET_ID_FILLED_BOX)
3052 draw_func = DrawFilledBox;
3053 else if (drawing_function == GADGET_ID_GRAB_BRUSH)
3054 draw_func = SelectArea;
3055 else /* (drawing_function == GADGET_ID_TEXT) */
3056 draw_func = SetTextCursor;
3058 if (button_press_event)
3060 draw_func(sx, sy, sx, sy, new_element, FALSE);
3061 start_sx = last_sx = sx;
3062 start_sy = last_sy = sy;
3064 if (drawing_function == GADGET_ID_TEXT)
3065 DrawLevelText(0, 0, 0, TEXT_END);
3067 else if (button_release_event)
3069 draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
3070 if (drawing_function == GADGET_ID_GRAB_BRUSH)
3072 CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
3073 CopyBrushToCursor(sx, sy);
3074 ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS]);
3075 draw_with_brush = TRUE;
3077 else if (drawing_function == GADGET_ID_TEXT)
3078 DrawLevelText(sx, sy, 0, TEXT_INIT);
3080 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3082 else if (last_sx != sx || last_sy != sy)
3084 draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
3085 draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
3092 case GADGET_ID_FLOOD_FILL:
3093 if (button_press_event && Feld[lx][ly] != new_element)
3095 FloodFill(lx, ly, new_element);
3096 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3097 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3101 case GADGET_ID_PICK_ELEMENT:
3102 if (button_press_event)
3103 PickDrawingElement(button, Feld[lx][ly]);
3104 if (button_release_event)
3105 ClickOnGadget(level_editor_gadget[last_drawing_function]);
3113 static void HandleCounterButtons(struct GadgetInfo *gi)
3115 int id = gi->custom_id;
3116 int button = gi->event.button;
3117 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3121 case GADGET_ID_ELEM_SCORE_DOWN:
3122 case GADGET_ID_ELEM_SCORE_UP:
3123 step *= (id == GADGET_ID_ELEM_SCORE_DOWN ? -1 : 1);
3124 ModifyEditorCounter(ED_COUNTER_ID_ELEM_SCORE,
3125 *gadget_elem_score_value + step);
3127 case GADGET_ID_ELEM_SCORE_TEXT:
3128 *gadget_elem_score_value = gi->text.number_value;
3131 case GADGET_ID_ELEM_CONTENT_DOWN:
3132 case GADGET_ID_ELEM_CONTENT_UP:
3133 step *= (id == GADGET_ID_ELEM_CONTENT_DOWN ? -1 : 1);
3134 ModifyEditorCounter(ED_COUNTER_ID_ELEM_CONTENT,
3135 *gadget_elem_content_value + step);
3136 DrawElementContentAreas();
3138 case GADGET_ID_ELEM_CONTENT_TEXT:
3139 *gadget_elem_content_value = gi->text.number_value;
3140 DrawElementContentAreas();
3143 case GADGET_ID_LEVEL_XSIZE_DOWN:
3144 case GADGET_ID_LEVEL_XSIZE_UP:
3145 step *= (id == GADGET_ID_LEVEL_XSIZE_DOWN ? -1 : 1);
3146 ModifyEditorCounter(ED_COUNTER_ID_LEVEL_XSIZE,
3147 *gadget_level_xsize_value + step);
3148 level.fieldx = lev_fieldx;
3150 case GADGET_ID_LEVEL_XSIZE_TEXT:
3151 *gadget_level_xsize_value = gi->text.number_value;
3152 level.fieldx = lev_fieldx;
3155 case GADGET_ID_LEVEL_YSIZE_DOWN:
3156 case GADGET_ID_LEVEL_YSIZE_UP:
3157 step *= (id == GADGET_ID_LEVEL_YSIZE_DOWN ? -1 : 1);
3158 ModifyEditorCounter(ED_COUNTER_ID_LEVEL_YSIZE,
3159 *gadget_level_ysize_value + step);
3160 level.fieldy = lev_fieldy;
3162 case GADGET_ID_LEVEL_YSIZE_TEXT:
3163 *gadget_level_ysize_value = gi->text.number_value;
3164 level.fieldy = lev_fieldy;
3167 case GADGET_ID_LEVEL_RANDOM_DOWN:
3168 case GADGET_ID_LEVEL_RANDOM_UP:
3169 step *= (id == GADGET_ID_LEVEL_RANDOM_DOWN ? -1 : 1);
3170 ModifyEditorCounter(ED_COUNTER_ID_LEVEL_RANDOM,
3171 *gadget_level_random_value + step);
3173 case GADGET_ID_LEVEL_RANDOM_TEXT:
3174 *gadget_level_random_value = gi->text.number_value;
3177 case GADGET_ID_LEVEL_COLLECT_DOWN:
3178 case GADGET_ID_LEVEL_COLLECT_UP:
3179 step *= (id == GADGET_ID_LEVEL_COLLECT_DOWN ? -1 : 1);
3180 ModifyEditorCounter(ED_COUNTER_ID_LEVEL_COLLECT,
3181 *gadget_level_collect_value + step);
3183 case GADGET_ID_LEVEL_COLLECT_TEXT:
3184 *gadget_level_collect_value = gi->text.number_value;
3187 case GADGET_ID_LEVEL_TIMELIMIT_DOWN:
3188 case GADGET_ID_LEVEL_TIMELIMIT_UP:
3189 step *= (id == GADGET_ID_LEVEL_TIMELIMIT_DOWN ? -1 : 1);
3190 ModifyEditorCounter(ED_COUNTER_ID_LEVEL_TIMELIMIT,
3191 *gadget_level_timelimit_value + step);
3193 case GADGET_ID_LEVEL_TIMELIMIT_TEXT:
3194 *gadget_level_timelimit_value = gi->text.number_value;
3197 case GADGET_ID_LEVEL_TIMESCORE_DOWN:
3198 case GADGET_ID_LEVEL_TIMESCORE_UP:
3199 step *= (id == GADGET_ID_LEVEL_TIMESCORE_DOWN ? -1 : 1);
3200 ModifyEditorCounter(ED_COUNTER_ID_LEVEL_TIMESCORE,
3201 *gadget_level_timescore_value + step);
3203 case GADGET_ID_LEVEL_TIMESCORE_TEXT:
3204 *gadget_level_timescore_value = gi->text.number_value;
3212 static void HandleTextInputGadgets(struct GadgetInfo *gi)
3214 int id = gi->custom_id;
3218 case GADGET_ID_LEVEL_NAME:
3219 strcpy(level.name, gi->text.value);
3222 case GADGET_ID_LEVEL_AUTHOR:
3223 strcpy(level.author, gi->text.value);
3231 static void HandleControlButtons(struct GadgetInfo *gi)
3233 int id = gi->custom_id;
3234 int button = gi->event.button;
3235 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3237 int player_present = FALSE;
3238 int level_changed = FALSE;
3241 new_element = (button == 1 ? new_element1 :
3242 button == 2 ? new_element2 :
3243 button == 3 ? new_element3 : 0);
3245 if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
3246 DrawLevelText(0, 0, 0, TEXT_END);
3248 if (id < ED_NUM_CTRL1_BUTTONS && id != GADGET_ID_PROPERTIES &&
3249 edit_mode != ED_MODE_DRAWING)
3251 DrawDrawingWindow();
3252 edit_mode = ED_MODE_DRAWING;
3257 case GADGET_ID_SCROLL_LEFT:
3258 if (level_xpos >= 0)
3260 int gadget_id = GADGET_ID_SCROLL_HORIZONTAL;
3261 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3263 if (lev_fieldx < ed_fieldx - 2)
3267 if (level_xpos < -1)
3270 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
3272 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3274 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
3278 case GADGET_ID_SCROLL_RIGHT:
3279 if (level_xpos <= lev_fieldx - ed_fieldx)
3281 int gadget_id = GADGET_ID_SCROLL_HORIZONTAL;
3282 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3284 if (lev_fieldx < ed_fieldx - 2)
3288 if (level_xpos > lev_fieldx - ed_fieldx + 1)
3289 level_xpos = lev_fieldx - ed_fieldx + 1;
3291 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
3293 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3295 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, level_xpos + 1, GDI_END);
3299 case GADGET_ID_SCROLL_UP:
3300 if (level_ypos >= 0)
3302 int gadget_id = GADGET_ID_SCROLL_VERTICAL;
3303 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3305 if (lev_fieldy < ed_fieldy - 2)
3309 if (level_ypos < -1)
3312 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
3314 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3316 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
3320 case GADGET_ID_SCROLL_DOWN:
3321 if (level_ypos <= lev_fieldy - ed_fieldy)
3323 int gadget_id = GADGET_ID_SCROLL_VERTICAL;
3324 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3326 if (lev_fieldy < ed_fieldy - 2)
3330 if (level_ypos > lev_fieldy - ed_fieldy + 1)
3331 level_ypos = lev_fieldy - ed_fieldy + 1;
3333 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
3335 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3337 ModifyGadget(gi, GDI_SCROLLBAR_ITEM_POSITION, level_ypos + 1, GDI_END);
3341 case GADGET_ID_SCROLL_HORIZONTAL:
3342 level_xpos = gi->event.item_position - 1;
3343 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3346 case GADGET_ID_SCROLL_VERTICAL:
3347 level_ypos = gi->event.item_position - 1;
3348 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3351 case GADGET_ID_ELEMENTLIST_UP:
3352 case GADGET_ID_ELEMENTLIST_DOWN:
3353 step *= (id == GADGET_ID_ELEMENTLIST_UP ? -1 : +1);
3354 element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
3356 if (element_shift < 0)
3358 if (element_shift > elements_in_list - ED_NUM_ELEMENTLIST_BUTTONS)
3359 element_shift = elements_in_list - ED_NUM_ELEMENTLIST_BUTTONS;
3361 for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
3363 int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
3364 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3365 struct GadgetDesign *design = &gi->deco.design;
3368 getMiniGraphicSource(el2gfx(editor_element[element_shift + i]),
3369 &design->pixmap, &design->x, &design->y);
3374 case GADGET_ID_WRAP_LEFT:
3375 WrapLevel(-step, 0);
3378 case GADGET_ID_WRAP_RIGHT:
3382 case GADGET_ID_WRAP_UP:
3383 WrapLevel(0, -step);
3386 case GADGET_ID_WRAP_DOWN:
3390 case GADGET_ID_SINGLE_ITEMS:
3391 case GADGET_ID_CONNECTED_ITEMS:
3392 case GADGET_ID_LINE:
3394 case GADGET_ID_TEXT:
3395 case GADGET_ID_RECTANGLE:
3396 case GADGET_ID_FILLED_BOX:
3397 case GADGET_ID_FLOOD_FILL:
3398 case GADGET_ID_GRAB_BRUSH:
3399 case GADGET_ID_PICK_ELEMENT:
3400 last_drawing_function = drawing_function;
3401 drawing_function = id;
3402 draw_with_brush = FALSE;
3405 case GADGET_ID_RANDOM_PLACEMENT:
3406 RandomPlacement(button);
3409 case GADGET_ID_PROPERTIES:
3410 if (edit_mode != ED_MODE_PROPERTIES)
3412 properties_element = new_element;
3413 DrawPropertiesWindow();
3414 edit_mode = ED_MODE_PROPERTIES;
3418 DrawDrawingWindow();
3419 edit_mode = ED_MODE_DRAWING;
3423 case GADGET_ID_UNDO:
3424 if (undo_buffer_steps == 0)
3426 Request("Undo buffer empty !", REQ_CONFIRM);
3430 undo_buffer_position =
3431 (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
3432 undo_buffer_steps--;
3434 for(x=0; x<lev_fieldx; x++)
3435 for(y=0; y<lev_fieldy; y++)
3436 Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
3437 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos,level_ypos);
3440 case GADGET_ID_INFO:
3441 if (edit_mode != ED_MODE_INFO)
3443 DrawLevelInfoWindow();
3444 edit_mode = ED_MODE_INFO;
3448 DrawDrawingWindow();
3449 edit_mode = ED_MODE_DRAWING;
3453 case GADGET_ID_CLEAR:
3454 for(x=0; x<MAX_LEV_FIELDX; x++)
3455 for(y=0; y<MAX_LEV_FIELDY; y++)
3456 Feld[x][y] = new_element3;
3457 CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
3459 DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
3462 case GADGET_ID_SAVE:
3463 if (leveldir[leveldir_nr].readonly)
3465 Request("This level is read only !", REQ_CONFIRM);
3469 for(y=0; y<lev_fieldy; y++)
3470 for(x=0; x<lev_fieldx; x++)
3471 if (Feld[x][y] != Ur[x][y])
3472 level_changed = TRUE;
3474 if (0 && !level_changed)
3476 Request("Level has not changed !", REQ_CONFIRM);
3480 for(y=0; y<lev_fieldy; y++)
3481 for(x=0; x<lev_fieldx; x++)
3482 if (Feld[x][y] == EL_SPIELFIGUR ||
3483 Feld[x][y] == EL_SPIELER1 ||
3484 Feld[x][y] == EL_SP_MURPHY)
3485 player_present = TRUE;
3487 if (!player_present)
3488 Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3491 if (Request("Save this level and kill the old ?", REQ_ASK))
3493 for(x=0; x<lev_fieldx; x++)
3494 for(y=0; y<lev_fieldy; y++)
3495 Ur[x][y] = Feld[x][y];
3496 SaveLevel(level_nr);
3501 case GADGET_ID_TEST:
3502 for(y=0; y<lev_fieldy; y++)
3503 for(x=0; x<lev_fieldx; x++)
3504 if (Feld[x][y] == EL_SPIELFIGUR ||
3505 Feld[x][y] == EL_SPIELER1 ||
3506 Feld[x][y] == EL_SP_MURPHY)
3507 player_present = TRUE;
3509 if (!player_present)
3510 Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3513 for(x=0; x<lev_fieldx; x++)
3514 for(y=0; y<lev_fieldy; y++)
3515 FieldBackup[x][y] = Ur[x][y];
3517 for(x=0; x<lev_fieldx; x++)
3518 for(y=0; y<lev_fieldy; y++)
3519 Ur[x][y] = Feld[x][y];
3521 UnmapLevelEditorGadgets();
3523 /* draw smaller door */
3524 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3525 DOOR_GFX_PAGEX7, 64,
3528 redraw_mask |= REDRAW_ALL;
3530 CloseDoor(DOOR_CLOSE_ALL);
3532 DrawCompleteVideoDisplay();
3534 if (setup.autorecord)
3535 TapeStartRecording();
3537 level_editor_test_game = TRUE;
3538 game_status = PLAYING;
3544 case GADGET_ID_EXIT:
3545 for(y=0; y<lev_fieldy; y++)
3546 for(x=0; x<lev_fieldx; x++)
3547 if (Feld[x][y] != Ur[x][y])
3548 level_changed = TRUE;
3550 if (!level_changed ||
3551 Request("Level has changed! Exit without saving ?",
3552 REQ_ASK | REQ_STAY_OPEN))
3554 CloseDoor(DOOR_CLOSE_1);
3557 CloseDoor(DOOR_CLOSE_ALL);
3560 /* draw smaller door */
3561 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3562 DOOR_GFX_PAGEX7, 64,
3565 redraw_mask |= REDRAW_ALL;
3567 game_status = MAINMENU;
3572 CloseDoor(DOOR_CLOSE_1);
3573 XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
3574 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
3575 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3576 OpenDoor(DOOR_OPEN_1);
3581 if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
3582 id <= GADGET_ID_ELEMENTLIST_LAST)
3584 int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
3585 int new_element = editor_element[element_position + element_shift];
3587 PickDrawingElement(button, new_element);
3589 if (!HAS_CONTENT(properties_element))
3591 properties_element = new_element;
3592 if (edit_mode == ED_MODE_PROPERTIES)
3593 DrawPropertiesWindow();
3597 else if (gi->event.type == GD_EVENT_PRESSED)
3598 printf("default: HandleControlButtons: GD_EVENT_PRESSED\n");
3599 else if (gi->event.type == GD_EVENT_RELEASED)
3600 printf("default: HandleControlButtons: GD_EVENT_RELEASED\n");
3601 else if (gi->event.type == GD_EVENT_MOVING)
3602 printf("default: HandleControlButtons: GD_EVENT_MOVING\n");
3604 printf("default: HandleControlButtons: ?\n");
3610 void HandleLevelEditorKeyInput(KeySym key)
3612 if (edit_mode == ED_MODE_DRAWING)
3614 char letter = getCharFromKeySym(key);
3616 if (drawing_function == GADGET_ID_TEXT)
3619 DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
3620 else if (key == XK_Delete || key == XK_BackSpace)
3621 DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
3622 else if (key == XK_Return)
3623 DrawLevelText(0, 0, 0, TEXT_NEWLINE);
3625 else if (button_status == MB_RELEASED)
3632 id = GADGET_ID_SCROLL_LEFT;
3635 id = GADGET_ID_SCROLL_RIGHT;
3638 id = GADGET_ID_SCROLL_UP;
3641 id = GADGET_ID_SCROLL_DOWN;
3645 id = GADGET_ID_NONE;
3649 if (id != GADGET_ID_NONE)
3650 ClickOnGadget(level_editor_gadget[id]);
3651 else if (letter == '.')
3652 ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS]);
3654 for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
3655 if (letter && letter == control_info[i].shortcut)
3656 ClickOnGadget(level_editor_gadget[i]);
3661 void ClearEditorGadgetInfoText()
3663 XFillRectangle(display, drawto, gc,
3664 INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
3665 redraw_mask |= REDRAW_FIELD;
3668 void HandleEditorGadgetInfoText(void *ptr)
3670 struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
3671 char infotext[MAX_INFOTEXT_LEN + 1];
3674 ClearEditorGadgetInfoText();
3676 /* misuse this function to delete brush cursor, if needed */
3677 if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
3678 DeleteBrushFromCursor();
3680 if (gi == NULL || gi->info_text == NULL)
3683 strncpy(infotext, gi->info_text, MAX_INFOTEXT_LEN);
3684 infotext[MAX_INFOTEXT_LEN] = '\0';
3686 if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
3688 int key = control_info[gi->custom_id].shortcut;
3692 sprintf(shortcut, " ('%s%c')",
3693 (key >= 'A' && key <= 'Z' ? "Shift-" :
3694 gi->custom_id == GADGET_ID_SINGLE_ITEMS ? ".' or '" : ""),
3697 if (strlen(infotext) + strlen(shortcut) <= MAX_INFOTEXT_LEN)
3698 strcat(infotext, shortcut);
3702 DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FS_SMALL, FC_YELLOW);
3705 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
3707 static int start_lx, start_ly;
3709 int id = gi->custom_id;
3710 int sx = gi->event.x;
3711 int sy = gi->event.y;
3712 int lx = sx + level_xpos;
3713 int ly = sy + level_ypos;
3715 ClearEditorGadgetInfoText();
3717 if (id == GADGET_ID_DRAWING_LEVEL)
3721 int min_sx = 0, min_sy = 0;
3722 int max_sx = gi->drawing.area_xsize - 1;
3723 int max_sy = gi->drawing.area_ysize - 1;
3724 int min_lx = 0, min_ly = 0;
3725 int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
3727 /* make sure to stay inside drawing area boundaries */
3728 sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
3729 sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
3731 /* get positions inside level field */
3732 lx = sx + level_xpos;
3733 ly = sy + level_ypos;
3735 /* make sure to stay inside level field boundaries */
3736 lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
3737 ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
3739 /* correct drawing area positions accordingly */
3740 sx = lx - level_xpos;
3741 sy = ly - level_ypos;
3744 if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
3746 if (button_status) /* if (gi->state == GD_BUTTON_PRESSED) */
3748 if (gi->event.type == GD_EVENT_PRESSED)
3754 switch (drawing_function)
3756 case GADGET_ID_SINGLE_ITEMS:
3757 infotext = "Drawing single items";
3759 case GADGET_ID_CONNECTED_ITEMS:
3760 infotext = "Drawing connected items";
3762 case GADGET_ID_LINE:
3763 infotext = "Drawing line";
3766 infotext = "Drawing arc";
3768 case GADGET_ID_TEXT:
3769 infotext = "Setting text cursor";
3771 case GADGET_ID_RECTANGLE:
3772 infotext = "Drawing rectangle";
3774 case GADGET_ID_FILLED_BOX:
3775 infotext = "Drawing filled box";
3777 case GADGET_ID_FLOOD_FILL:
3778 infotext = "Flood fill";
3780 case GADGET_ID_GRAB_BRUSH:
3781 infotext = "Grabbing brush";
3783 case GADGET_ID_PICK_ELEMENT:
3784 infotext = "Picking element";
3788 infotext = "Drawing position";
3792 DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3793 "%s: %d, %d", infotext,
3794 ABS(lx - start_lx) + 1,
3795 ABS(ly - start_ly) + 1);
3798 DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3799 "Level position: %d, %d", lx, ly);
3802 /* misuse this function to draw brush cursor, if needed */
3803 if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
3805 if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
3806 CopyBrushToCursor(sx, sy);
3808 DeleteBrushFromCursor();
3811 else if (id == GADGET_ID_AMOEBA_CONTENT)
3812 DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3815 DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3816 "Cruncher %d content: %d, %d",
3817 id - GADGET_ID_ELEM_CONTENT_0 + 1, sx, sy);