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 ***********************************************************/
23 /* positions in the level editor */
24 #define ED_WIN_MB_LEFT_XPOS 7
25 #define ED_WIN_MB_LEFT_YPOS 6
26 #define ED_WIN_LEVELNR_XPOS 77
27 #define ED_WIN_LEVELNR_YPOS 7
28 #define ED_WIN_MB_MIDDLE_XPOS 7
29 #define ED_WIN_MB_MIDDLE_YPOS 258
30 #define ED_WIN_MB_RIGHT_XPOS 77
31 #define ED_WIN_MB_RIGHT_YPOS 258
33 /* other constants for the editor */
34 #define ED_SCROLL_NO 0
35 #define ED_SCROLL_LEFT 1
36 #define ED_SCROLL_RIGHT 2
37 #define ED_SCROLL_UP 4
38 #define ED_SCROLL_DOWN 8
40 /* screens in the level editor */
41 #define ED_MODE_DRAWING 0
42 #define ED_MODE_INFO 1
43 #define ED_MODE_PROPERTIES 2
45 /* how many steps can be cancelled */
46 #define NUM_UNDO_STEPS (10 + 1)
48 /* values for random placement */
49 #define RANDOM_USE_PERCENTAGE 0
50 #define RANDOM_USE_NUM_OBJECTS 1
52 /* values for elements with score */
56 /* values for elements with content */
57 #define MIN_ELEMCONT 1
58 #define MAX_ELEMCONT 8
60 /* values for the control window */
61 #define ED_CTRL_BUTTONS_GFX_YPOS 236
62 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS 142
64 #define ED_CTRL1_BUTTONS_HORIZ 4
65 #define ED_CTRL1_BUTTONS_VERT 4
66 #define ED_CTRL1_BUTTON_XSIZE 22
67 #define ED_CTRL1_BUTTON_YSIZE 22
68 #define ED_CTRL1_BUTTONS_XPOS 6
69 #define ED_CTRL1_BUTTONS_YPOS 6
70 #define ED_CTRL2_BUTTONS_HORIZ 3
71 #define ED_CTRL2_BUTTONS_VERT 2
72 #define ED_CTRL2_BUTTON_XSIZE 30
73 #define ED_CTRL2_BUTTON_YSIZE 20
74 #define ED_CTRL2_BUTTONS_XPOS 5
75 #define ED_CTRL2_BUTTONS_YPOS 100
76 #define ED_NUM_CTRL1_BUTTONS (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
77 #define ED_NUM_CTRL2_BUTTONS (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
78 #define ED_NUM_CTRL_BUTTONS (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
80 /* values for properties window */
81 #define ED_PROPERTIES_XPOS (TILEX - MINI_TILEX/2)
83 /* values for counter gadgets */
84 #define ED_COUNT_VALUE_XOFFSET 5
85 #define ED_COUNT_VALUE_YOFFSET 3
86 #define ED_COUNT_SCORE_XPOS ED_PROPERTIES_XPOS
87 #define ED_COUNT_SCORE_YPOS (14 * MINI_TILEY)
88 #define ED_COUNT_ELEMCONT_XPOS ED_PROPERTIES_XPOS
89 #define ED_COUNT_ELEMCONT_YPOS (17 * MINI_TILEY)
91 /* standard distances */
92 #define ED_BORDER_SIZE 3
93 #define ED_GADGET_DISTANCE 2
95 /* values for element content drawing areas */
96 #define ED_AREA_ELEMCONT_XPOS (TILEX)
97 #define ED_AREA_ELEMCONT_YPOS (10 * TILEY)
99 /* values for scrolling gadgets */
100 #define ED_SCROLLBUTTON_XPOS 24
101 #define ED_SCROLLBUTTON_YPOS 0
102 #define ED_SCROLLBAR_XPOS 24
103 #define ED_SCROLLBAR_YPOS 64
105 #define ED_SCROLLBUTTON_XSIZE 16
106 #define ED_SCROLLBUTTON_YSIZE 16
108 #define ED_SCROLL_UP_XPOS (SXSIZE - ED_SCROLLBUTTON_XSIZE)
109 #define ED_SCROLL_UP_YPOS (0)
110 #define ED_SCROLL_DOWN_XPOS ED_SCROLL_UP_XPOS
111 #define ED_SCROLL_DOWN_YPOS (SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
112 #define ED_SCROLL_LEFT_XPOS (0)
113 #define ED_SCROLL_LEFT_YPOS (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
114 #define ED_SCROLL_RIGHT_XPOS (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
115 #define ED_SCROLL_RIGHT_YPOS ED_SCROLL_LEFT_YPOS
116 #define ED_SCROLL_VERTICAL_XPOS ED_SCROLL_UP_XPOS
117 #define ED_SCROLL_VERTICAL_YPOS (ED_SCROLL_UP_YPOS + ED_SCROLLBUTTON_YSIZE)
118 #define ED_SCROLL_VERTICAL_XSIZE ED_SCROLLBUTTON_XSIZE
119 #define ED_SCROLL_VERTICAL_YSIZE (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
120 #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + ED_SCROLLBUTTON_XSIZE)
121 #define ED_SCROLL_HORIZONTAL_YPOS ED_SCROLL_LEFT_YPOS
122 #define ED_SCROLL_HORIZONTAL_XSIZE (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
123 #define ED_SCROLL_HORIZONTAL_YSIZE ED_SCROLLBUTTON_YSIZE
125 /* control button identifiers */
126 #define ED_CTRL_ID_NONE -1
128 #define ED_CTRL_ID_SINGLE_ITEMS 0
129 #define ED_CTRL_ID_CONNECTED_ITEMS 1
130 #define ED_CTRL_ID_LINE 2
131 #define ED_CTRL_ID_TEXT 3
132 #define ED_CTRL_ID_RECTANGLE 4
133 #define ED_CTRL_ID_FILLED_BOX 5
134 #define ED_CTRL_ID_WRAP_UP 6
135 #define ED_CTRL_ID_PROPERTIES 7
136 #define ED_CTRL_ID_FLOOD_FILL 8
137 #define ED_CTRL_ID_WRAP_LEFT 9
138 #define ED_CTRL_ID_UNUSED1 10
139 #define ED_CTRL_ID_WRAP_RIGHT 11
140 #define ED_CTRL_ID_RANDOM_PLACEMENT 12
141 #define ED_CTRL_ID_GRAB_BRUSH 13
142 #define ED_CTRL_ID_WRAP_DOWN 14
143 #define ED_CTRL_ID_PICK_ELEMENT 15
144 #define ED_CTRL_ID_UNDO 16
145 #define ED_CTRL_ID_INFO 17
146 #define ED_CTRL_ID_SAVE 18
147 #define ED_CTRL_ID_CLEAR 19
148 #define ED_CTRL_ID_TEST 20
149 #define ED_CTRL_ID_EXIT 21
151 /* counter button identifiers */
152 #define ED_CTRL_ID_SCORE_DOWN 22
153 #define ED_CTRL_ID_SCORE_TEXT 23
154 #define ED_CTRL_ID_SCORE_UP 24
155 #define ED_CTRL_ID_ELEMCONT_DOWN 25
156 #define ED_CTRL_ID_ELEMCONT_TEXT 26
157 #define ED_CTRL_ID_ELEMCONT_UP 27
159 /* drawing area identifiers */
160 #define ED_CTRL_ID_DRAWING_LEVEL 28
161 #define ED_CTRL_ID_ELEMCONT_0 29
162 #define ED_CTRL_ID_ELEMCONT_1 30
163 #define ED_CTRL_ID_ELEMCONT_2 31
164 #define ED_CTRL_ID_ELEMCONT_3 32
165 #define ED_CTRL_ID_ELEMCONT_4 33
166 #define ED_CTRL_ID_ELEMCONT_5 34
167 #define ED_CTRL_ID_ELEMCONT_6 35
168 #define ED_CTRL_ID_ELEMCONT_7 36
169 #define ED_CTRL_ID_AMOEBA_CONTENT 37
171 /* text input identifiers */
172 #define ED_CTRL_ID_LEVEL_NAME 38
174 /* gadgets for scrolling of drawing area */
175 #define ED_CTRL_ID_SCROLL_UP 39
176 #define ED_CTRL_ID_SCROLL_DOWN 40
177 #define ED_CTRL_ID_SCROLL_LEFT 41
178 #define ED_CTRL_ID_SCROLL_RIGHT 42
179 #define ED_CTRL_ID_SCROLL_VERTICAL 43
180 #define ED_CTRL_ID_SCROLL_HORIZONTAL 44
182 #define ED_NUM_GADGETS 45
184 /* values for counter gadgets */
185 #define ED_COUNTER_ID_SCORE 0
186 #define ED_COUNTER_ID_ELEMCONT 1
188 #define ED_NUM_COUNTERBUTTONS 2
189 #define ED_NUM_SCROLLBUTTONS 4
190 #define ED_NUM_SCROLLBARS 2
192 /* values for CopyLevelToUndoBuffer() */
193 #define UNDO_IMMEDIATE 0
194 #define UNDO_ACCUMULATE 1
200 } control_info[ED_NUM_CTRL_BUTTONS] =
202 { 's', "draw single items" },
203 { 'd', "draw connected items" },
204 { 'l', "draw lines" },
205 { 't', "enter text elements" },
206 { 'r', "draw outline rectangles" },
207 { 'R', "draw filled rectangles" },
208 { '\0', "wrap (rotate) level up" },
209 { '?', "properties of drawing element" },
210 { 'f', "flood fill" },
211 { '\0', "wrap (rotate) level left" },
213 { '\0', "wrap (rotate) level right" },
214 { '\0', "random element placement" },
215 { 'b', "grab brush" },
216 { '\0', "wrap (rotate) level down" },
217 { ',', "pick drawing element" },
218 { 'U', "undo last operation" },
219 { 'I', "level properties" },
220 { 'S', "save level" },
221 { 'C', "clear level" },
222 { 'T', "test level" },
223 { 'E', "exit level editor" }
226 /* pointers to counter values */
227 static int *gadget_score_value = NULL;
228 static int *gadget_areas_value = NULL;
234 int min_value, max_value;
235 int gadget_id_down, gadget_id_up;
237 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
239 { ED_COUNT_SCORE_XPOS, ED_COUNT_SCORE_YPOS,
241 MIN_SCORE, MAX_SCORE,
242 ED_CTRL_ID_SCORE_DOWN, ED_CTRL_ID_SCORE_UP,
243 ED_CTRL_ID_SCORE_TEXT },
244 { ED_COUNT_ELEMCONT_XPOS, ED_COUNT_ELEMCONT_YPOS,
246 MIN_ELEMCONT, MAX_ELEMCONT,
247 ED_CTRL_ID_ELEMCONT_DOWN, ED_CTRL_ID_ELEMCONT_UP,
248 ED_CTRL_ID_ELEMCONT_TEXT }
257 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
260 ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE,
261 ED_SCROLL_UP_XPOS, ED_SCROLL_UP_YPOS, ED_CTRL_ID_SCROLL_UP,
262 "scroll level editing area up"
265 ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
266 ED_SCROLL_DOWN_XPOS, ED_SCROLL_DOWN_YPOS, ED_CTRL_ID_SCROLL_DOWN,
267 "scroll level editing area down"
270 ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
271 ED_SCROLL_LEFT_XPOS, ED_SCROLL_LEFT_YPOS, ED_CTRL_ID_SCROLL_LEFT,
272 "scroll level editing area left"
275 ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
276 ED_SCROLL_RIGHT_XPOS, ED_SCROLL_RIGHT_YPOS, ED_CTRL_ID_SCROLL_RIGHT,
277 "scroll level editing area right"
289 } scrollbar_info[ED_NUM_SCROLLBARS] =
292 ED_SCROLLBAR_XPOS, ED_SCROLLBAR_YPOS,
293 ED_SCROLL_VERTICAL_XPOS, ED_SCROLL_VERTICAL_YPOS,
294 ED_SCROLL_VERTICAL_XSIZE, ED_SCROLL_VERTICAL_YSIZE,
295 GD_TYPE_SCROLLBAR_VERTICAL,
296 ED_CTRL_ID_SCROLL_VERTICAL,
297 "scroll level editing area vertically"
300 ED_SCROLLBAR_XPOS, ED_SCROLLBAR_YPOS,
301 ED_SCROLL_HORIZONTAL_XPOS, ED_SCROLL_HORIZONTAL_YPOS,
302 ED_SCROLL_HORIZONTAL_XSIZE, ED_SCROLL_HORIZONTAL_YSIZE,
303 GD_TYPE_SCROLLBAR_HORIZONTAL,
304 ED_CTRL_ID_SCROLL_HORIZONTAL,
305 "scroll level editing area horizontally"
309 /* forward declaration for internal use */
310 static void DrawDrawingWindow();
311 static void DrawPropertiesWindow();
312 static void CopyLevelToUndoBuffer(int);
313 static void HandleControlButtons(struct GadgetInfo *);
314 static void HandleCounterButtons(struct GadgetInfo *);
315 static void HandleDrawingAreas(struct GadgetInfo *);
316 static void HandleDrawingAreaInfo(struct GadgetInfo *);
317 static void HandleTextInputGadgets(struct GadgetInfo *);
319 static struct GadgetInfo *level_editor_gadget[ED_NUM_GADGETS];
320 static boolean level_editor_gadgets_created = FALSE;
322 static int drawing_function = ED_CTRL_ID_SINGLE_ITEMS;
323 static int last_drawing_function = ED_CTRL_ID_SINGLE_ITEMS;
324 static boolean draw_with_brush = FALSE;
325 static int properties_element = 0;
327 static short ElementContent[MAX_ELEMCONT][3][3];
328 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
329 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
330 static int undo_buffer_position = 0;
331 static int undo_buffer_steps = 0;
333 static int random_placement_percentage = 10;
334 static int random_placement_num_objects = 10;
336 static int random_placement_method = RANDOM_USE_PERCENTAGE;
338 static int random_placement_method = RANDOM_USE_NUM_OBJECTS;
341 static int level_xpos,level_ypos;
342 static int edit_mode;
343 static boolean name_typing;
344 static int new_element1 = EL_MAUERWERK;
345 static int new_element2 = EL_LEERRAUM;
346 static int new_element3 = EL_ERDREICH;
348 int element_shift = 0;
350 int editor_element[] =
352 EL_CHAR_A + ('B' - 'A'),
353 EL_CHAR_A + ('O' - 'A'),
354 EL_CHAR_A + ('U' - 'A'),
355 EL_CHAR_A + ('L' - 'A'),
358 EL_CHAR_A + ('D' - 'A'),
359 EL_CHAR_A + ('E' - 'A'),
360 EL_CHAR_A + ('R' - 'A'),
362 EL_CHAR_A + ('D' - 'A'),
363 EL_CHAR_A + ('A' - 'A'),
364 EL_CHAR_A + ('S' - 'A'),
365 EL_CHAR_A + ('H' - 'A'),
392 EL_CHAR_A + ('E' - 'A'),
393 EL_CHAR_A + ('M' - 'A'),
394 EL_CHAR_A + ('E' - 'A'),
397 EL_CHAR_A + ('R' - 'A'),
398 EL_CHAR_A + ('A' - 'A'),
399 EL_CHAR_A + ('L' - 'A'),
400 EL_CHAR_A + ('D' - 'A'),
402 EL_CHAR_A + ('M' - 'A'),
403 EL_CHAR_A + ('I' - 'A'),
404 EL_CHAR_A + ('N' - 'A'),
405 EL_CHAR_A + ('E' - 'A'),
482 EL_CHAR_A + ('M' - 'A'),
483 EL_CHAR_A + ('O' - 'A'),
484 EL_CHAR_A + ('R' - 'A'),
485 EL_CHAR_A + ('E' - 'A'),
537 EL_CHAR_A + ('S' - 'A'),
538 EL_CHAR_A + ('O' - 'A'),
539 EL_CHAR_A + ('K' - 'A'),
540 EL_CHAR_A + ('O' - 'A'),
543 EL_CHAR_A + ('B' - 'A'),
544 EL_CHAR_A + ('A' - 'A'),
545 EL_CHAR_A + ('N' - 'A'),
548 EL_SOKOBAN_FELD_LEER,
549 EL_SOKOBAN_FELD_VOLL,
618 EL_CHAR_A + ('D' - 'A'),
619 EL_CHAR_A + ('Y' - 'A'),
620 EL_CHAR_A + ('N' - 'A'),
621 EL_CHAR_A + ('A' - 'A'),
623 EL_CHAR_A + ('B' - 'A'),
624 EL_CHAR_A + ('L' - 'A'),
625 EL_CHAR_A + ('A' - 'A'),
626 EL_CHAR_A + ('S' - 'A'),
629 EL_CHAR_A + ('T' - 'A'),
630 EL_CHAR_A + ('E' - 'A'),
631 EL_CHAR_A + ('R' - 'A'),
714 int elements_in_list = sizeof(editor_element)/sizeof(int);
716 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
719 int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
720 int dy = (scroll == ED_SCROLL_UP ? -1 : scroll == ED_SCROLL_DOWN ? 1 : 0);
722 XCopyArea(display, drawto, drawto, gc,
723 SX + (dx == -1 ? MINI_TILEX : 0),
724 SY + (dy == -1 ? MINI_TILEY : 0),
725 (ED_FIELDX * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
726 (ED_FIELDY * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
727 SX + (dx == +1 ? MINI_TILEX : 0),
728 SY + (dy == +1 ? MINI_TILEY : 0));
731 x = (dx == 1 ? 0 : ED_FIELDX - 1);
732 for(y=0; y<ED_FIELDY; y++)
733 DrawMiniElementOrWall(x, y, from_x, from_y);
737 y = (dy == 1 ? 0 : ED_FIELDY - 1);
738 for(x=0; x<ED_FIELDX; x++)
739 DrawMiniElementOrWall(x, y, from_x, from_y);
742 redraw_mask |= REDRAW_FIELD;
746 void InitLevelEditorGadgets()
750 for (i=0; i<ED_NUM_GADGETS; i++)
751 level_editor_gadget[i] = NULL;
754 static void CreateControlButtons()
756 Pixmap gd_pixmap = pix[PIX_DOOR];
757 struct GadgetInfo *gi;
758 unsigned long event_mask;
761 /* create toolbox buttons */
762 for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
766 int gd_xoffset, gd_yoffset;
767 int gd_x1, gd_x2, gd_y1, gd_y2;
770 boolean radio_button_pressed;
772 if (id == ED_CTRL_ID_SINGLE_ITEMS ||
773 id == ED_CTRL_ID_CONNECTED_ITEMS ||
774 id == ED_CTRL_ID_LINE ||
775 id == ED_CTRL_ID_TEXT ||
776 id == ED_CTRL_ID_RECTANGLE ||
777 id == ED_CTRL_ID_FILLED_BOX ||
778 id == ED_CTRL_ID_FLOOD_FILL ||
779 id == ED_CTRL_ID_GRAB_BRUSH ||
780 id == ED_CTRL_ID_PICK_ELEMENT)
782 button_type = GD_TYPE_RADIO_BUTTON;
784 radio_button_pressed = (id == drawing_function ? TRUE : FALSE);
785 event_mask = GD_EVENT_PRESSED;
789 button_type = GD_TYPE_NORMAL_BUTTON;
791 radio_button_pressed = FALSE;
793 if (id == ED_CTRL_ID_WRAP_LEFT ||
794 id == ED_CTRL_ID_WRAP_RIGHT ||
795 id == ED_CTRL_ID_WRAP_UP ||
796 id == ED_CTRL_ID_WRAP_DOWN)
797 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
799 event_mask = GD_EVENT_RELEASED;
802 if (id < ED_NUM_CTRL1_BUTTONS)
804 int x = i % ED_CTRL1_BUTTONS_HORIZ;
805 int y = i / ED_CTRL1_BUTTONS_HORIZ;
807 gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
808 gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
809 width = ED_CTRL1_BUTTON_XSIZE;
810 height = ED_CTRL1_BUTTON_YSIZE;
814 int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
815 int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
817 gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
818 gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
819 width = ED_CTRL2_BUTTON_XSIZE;
820 height = ED_CTRL2_BUTTON_YSIZE;
823 gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
824 gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
825 gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_GFX_YPOS + gd_yoffset;
826 gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
828 gi = CreateGadget(GDI_CUSTOM_ID, id,
829 GDI_DESCRIPTION_TEXT, control_info[i].text,
830 GDI_X, EX + gd_xoffset,
831 GDI_Y, EY + gd_yoffset,
834 GDI_TYPE, button_type,
835 GDI_STATE, GD_BUTTON_UNPRESSED,
836 GDI_RADIO_NR, radio_button_nr,
837 GDI_RADIO_PRESSED, radio_button_pressed,
838 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
839 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
840 GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
841 GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
842 GDI_EVENT_MASK, event_mask,
843 GDI_CALLBACK_ACTION, HandleControlButtons,
847 Error(ERR_EXIT, "cannot create gadget");
849 level_editor_gadget[id] = gi;
852 /* create buttons for scrolling of drawing area */
853 for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
855 int id = scrollbutton_info[i].gadget_id;
856 int gd_x1, gd_x2, gd_y;
858 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
860 gd_y = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
861 gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].xpos;
862 gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
864 gi = CreateGadget(GDI_CUSTOM_ID, id,
865 GDI_DESCRIPTION_TEXT, scrollbutton_info[i].text,
866 GDI_X, SX + scrollbutton_info[i].x,
867 GDI_Y, SY + scrollbutton_info[i].y,
868 GDI_WIDTH, ED_SCROLLBUTTON_XSIZE,
869 GDI_HEIGHT, ED_SCROLLBUTTON_YSIZE,
870 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
871 GDI_STATE, GD_BUTTON_UNPRESSED,
872 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
873 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
874 GDI_EVENT_MASK, event_mask,
875 GDI_CALLBACK_ACTION, HandleControlButtons,
879 Error(ERR_EXIT, "cannot create gadget");
881 level_editor_gadget[id] = gi;
885 static void CreateCounterButtons()
889 for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
892 int xpos = SX + counterbutton_info[i].x; /* xpos of down count button */
893 int ypos = SY + counterbutton_info[i].y;
897 Pixmap gd_pixmap = pix[PIX_DOOR];
898 struct GadgetInfo *gi;
900 counterbutton_info[i].gadget_id_down :
901 counterbutton_info[i].gadget_id_up);
903 int gd_x, gd_x1, gd_x2, gd_y;
904 unsigned long event_mask;
906 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
908 gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
909 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
910 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
911 gd_y = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
913 gi = CreateGadget(GDI_CUSTOM_ID, id,
916 GDI_WIDTH, ED_BUTTON_COUNT_XSIZE,
917 GDI_HEIGHT, ED_BUTTON_COUNT_YSIZE,
918 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
919 GDI_STATE, GD_BUTTON_UNPRESSED,
920 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
921 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
922 GDI_EVENT_MASK, event_mask,
923 GDI_CALLBACK_ACTION, HandleCounterButtons,
927 Error(ERR_EXIT, "cannot create gadget");
929 level_editor_gadget[id] = gi;
930 xpos += gi->width + ED_GADGET_DISTANCE; /* xpos of text count button */
934 id = counterbutton_info[i].gadget_id_text;
935 event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
937 gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
938 gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
940 gi = CreateGadget(GDI_CUSTOM_ID, id,
943 GDI_TYPE, GD_TYPE_TEXTINPUT_NUMERIC,
945 GDI_NUMBER_MIN, counterbutton_info[i].min_value,
946 GDI_NUMBER_MAX, counterbutton_info[i].max_value,
948 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
949 GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
950 GDI_DESIGN_BORDER, ED_BORDER_SIZE,
951 GDI_EVENT_MASK, event_mask,
952 GDI_CALLBACK_ACTION, HandleCounterButtons,
956 Error(ERR_EXIT, "cannot create gadget");
958 level_editor_gadget[id] = gi;
959 xpos += gi->width + ED_GADGET_DISTANCE; /* xpos of up count button */
965 static void CreateDrawingAreas()
967 struct GadgetInfo *gi;
968 unsigned long event_mask;
973 GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
974 GD_EVENT_OFF_BORDERS;
976 /* one for the level drawing area ... */
977 id = ED_CTRL_ID_DRAWING_LEVEL;
978 gi = CreateGadget(GDI_CUSTOM_ID, id,
981 GDI_TYPE, GD_TYPE_DRAWING_AREA,
982 GDI_AREA_SIZE, ED_FIELDX, ED_FIELDY,
983 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
984 GDI_EVENT_MASK, event_mask,
985 GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
986 GDI_CALLBACK_ACTION, HandleDrawingAreas,
990 Error(ERR_EXIT, "cannot create gadget");
992 level_editor_gadget[id] = gi;
994 /* ... up to eight areas for element content ... */
995 for (i=0; i<MAX_ELEMCONT; i++)
997 int gx = SX + ED_AREA_ELEMCONT_XPOS + 5 * (i % 4) * MINI_TILEX;
998 int gy = SX + ED_AREA_ELEMCONT_YPOS + 6 * (i / 4) * MINI_TILEY;
1000 id = ED_CTRL_ID_ELEMCONT_0 + i;
1001 gi = CreateGadget(GDI_CUSTOM_ID, id,
1004 GDI_WIDTH, 3 * MINI_TILEX,
1005 GDI_HEIGHT, 3 * MINI_TILEY,
1006 GDI_TYPE, GD_TYPE_DRAWING_AREA,
1007 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1008 GDI_EVENT_MASK, event_mask,
1009 GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1010 GDI_CALLBACK_ACTION, HandleDrawingAreas,
1014 Error(ERR_EXIT, "cannot create gadget");
1016 level_editor_gadget[id] = gi;
1019 /* ... and one for the amoeba content */
1020 id = ED_CTRL_ID_AMOEBA_CONTENT;
1021 gi = CreateGadget(GDI_CUSTOM_ID, id,
1022 GDI_X, SX + ED_AREA_ELEMCONT_XPOS,
1023 GDI_Y, SY + ED_AREA_ELEMCONT_YPOS,
1024 GDI_WIDTH, MINI_TILEX,
1025 GDI_HEIGHT, MINI_TILEY,
1026 GDI_TYPE, GD_TYPE_DRAWING_AREA,
1027 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1028 GDI_EVENT_MASK, event_mask,
1029 GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1030 GDI_CALLBACK_ACTION, HandleDrawingAreas,
1034 Error(ERR_EXIT, "cannot create gadget");
1036 level_editor_gadget[id] = gi;
1039 static void CreateTextInputGadgets()
1041 Pixmap gd_pixmap = pix[PIX_DOOR];
1043 struct GadgetInfo *gi;
1044 unsigned long event_mask;
1047 event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
1049 gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
1050 gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
1052 /* text input gadget for the level name */
1053 id = ED_CTRL_ID_LEVEL_NAME;
1054 gi = CreateGadget(GDI_CUSTOM_ID, id,
1055 GDI_X, SX + ED_COUNT_ELEMCONT_XPOS,
1056 GDI_Y, SY + ED_AREA_ELEMCONT_YPOS + 3 * TILEX,
1057 GDI_TYPE, GD_TYPE_TEXTINPUT_ALPHANUMERIC,
1058 GDI_TEXT_VALUE, level.name,
1060 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
1061 GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
1062 GDI_DESIGN_BORDER, ED_BORDER_SIZE,
1063 GDI_EVENT_MASK, event_mask,
1064 GDI_CALLBACK_ACTION, HandleTextInputGadgets,
1068 Error(ERR_EXIT, "cannot create gadget");
1070 level_editor_gadget[id] = gi;
1073 static void CreateScrollbarGadgets()
1077 for (i=0; i<ED_NUM_SCROLLBARS; i++)
1079 int id = scrollbar_info[i].gadget_id;
1080 Pixmap gd_pixmap = pix[PIX_DOOR];
1081 int gd_x1, gd_x2, gd_y1, gd_y2;
1082 struct GadgetInfo *gi;
1083 int items_max, items_visible, item_position;
1084 unsigned long event_mask;
1086 if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
1088 items_max = lev_fieldx + 2;
1089 items_visible = ED_FIELDX;
1094 items_max = lev_fieldy + 2;
1095 items_visible = ED_FIELDY;
1099 event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
1101 gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].xpos;
1102 gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
1103 gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1104 gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1106 gi = CreateGadget(GDI_CUSTOM_ID, id,
1107 GDI_DESCRIPTION_TEXT, scrollbar_info[i].text,
1108 GDI_X, SX + scrollbar_info[i].x,
1109 GDI_Y, SY + scrollbar_info[i].y,
1110 GDI_WIDTH, scrollbar_info[i].width,
1111 GDI_HEIGHT, scrollbar_info[i].height,
1112 GDI_TYPE, scrollbar_info[i].type,
1113 GDI_SCROLLBAR_ITEMS_MAX, items_max,
1114 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1115 GDI_SCROLLBAR_ITEM_POSITION, item_position,
1116 GDI_STATE, GD_BUTTON_UNPRESSED,
1117 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1118 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1119 GDI_DESIGN_BORDER, ED_BORDER_SIZE,
1120 GDI_EVENT_MASK, event_mask,
1121 GDI_CALLBACK_ACTION, HandleControlButtons,
1125 Error(ERR_EXIT, "cannot create gadget");
1127 level_editor_gadget[id] = gi;
1131 static void CreateLevelEditorGadgets()
1133 if (level_editor_gadgets_created)
1136 CreateControlButtons();
1137 CreateCounterButtons();
1138 CreateDrawingAreas();
1139 CreateTextInputGadgets();
1140 CreateScrollbarGadgets();
1142 level_editor_gadgets_created = TRUE;
1145 static void MapControlButtons()
1149 for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
1150 MapGadget(level_editor_gadget[i]);
1153 static void MapCounterButtons(int cnt_id)
1155 MapGadget(level_editor_gadget[counterbutton_info[cnt_id].gadget_id_down]);
1156 MapGadget(level_editor_gadget[counterbutton_info[cnt_id].gadget_id_text]);
1157 MapGadget(level_editor_gadget[counterbutton_info[cnt_id].gadget_id_up]);
1160 static void MapDrawingArea(int id)
1162 MapGadget(level_editor_gadget[id]);
1165 static void MapTextInputGadget(int id)
1167 MapGadget(level_editor_gadget[id]);
1170 static void MapMainDrawingArea()
1174 for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
1175 MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
1177 for (i=0; i<ED_NUM_SCROLLBARS; i++)
1178 MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
1180 MapDrawingArea(ED_CTRL_ID_DRAWING_LEVEL);
1183 static void UnmapDrawingArea(int id)
1185 UnmapGadget(level_editor_gadget[id]);
1188 void UnmapLevelEditorWindowGadgets()
1192 for (i=ED_NUM_CTRL_BUTTONS; i<ED_NUM_GADGETS; i++)
1193 UnmapGadget(level_editor_gadget[i]);
1196 void UnmapLevelEditorGadgets()
1200 for (i=0; i<ED_NUM_GADGETS; i++)
1201 UnmapGadget(level_editor_gadget[i]);
1206 int i, x, y, graphic;
1208 edit_mode = ED_MODE_DRAWING;
1209 name_typing = FALSE;
1211 CloseDoor(DOOR_CLOSE_ALL);
1213 OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
1215 if (level_editor_test_game)
1217 for(x=0; x<lev_fieldx; x++)
1218 for(y=0; y<lev_fieldy; y++)
1219 Feld[x][y] = Ur[x][y];
1221 for(x=0; x<lev_fieldx; x++)
1222 for(y=0; y<lev_fieldy; y++)
1223 Ur[x][y] = FieldBackup[x][y];
1225 level_editor_test_game = FALSE;
1231 undo_buffer_position = -1;
1232 undo_buffer_steps = -1;
1233 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
1237 DrawMiniLevel(level_xpos, level_ypos);
1241 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1242 DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY1,
1244 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1245 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1246 DOOR_GFX_PAGEX6+ED_BUTTON_ELEM_XPOS,
1247 DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS,
1248 4*ED_BUTTON_ELEM_XSIZE,5*ED_BUTTON_ELEM_YSIZE,
1249 DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS,
1250 DOOR_GFX_PAGEY1+ED_BUTTON_EUP_Y2POS);
1252 for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1254 if (i < elements_in_list)
1255 graphic = el2gfx(editor_element[i + element_shift]);
1257 graphic = GFX_LEERRAUM;
1259 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1260 DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS+3 +
1261 (i%MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
1262 DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS+3 +
1263 (i/MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
1267 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1268 DOOR_GFX_PAGEX1+ED_WIN_MB_LEFT_XPOS,
1269 DOOR_GFX_PAGEY1+ED_WIN_MB_LEFT_YPOS,
1270 el2gfx(new_element1));
1271 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1272 DOOR_GFX_PAGEX1+ED_WIN_MB_MIDDLE_XPOS,
1273 DOOR_GFX_PAGEY1+ED_WIN_MB_MIDDLE_YPOS,
1274 el2gfx(new_element2));
1275 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1276 DOOR_GFX_PAGEX1+ED_WIN_MB_RIGHT_XPOS,
1277 DOOR_GFX_PAGEY1+ED_WIN_MB_RIGHT_YPOS,
1278 el2gfx(new_element3));
1279 DrawTextExt(pix[PIX_DB_DOOR],gc,
1280 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS,
1281 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1282 int2str(level_nr,2),FS_SMALL,FC_SPECIAL1);
1283 XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1284 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+3,
1285 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1287 DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS,
1288 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1289 XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1290 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+14,
1291 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1293 DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS+9,
1294 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1296 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1297 DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1299 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1301 /* draw bigger door */
1302 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1307 /* draw new control window */
1308 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1309 DOOR_GFX_PAGEX8, 236,
1313 redraw_mask |= REDRAW_ALL;
1315 OpenDoor(DOOR_OPEN_1);
1317 if (!level_editor_gadgets_created)
1318 CreateLevelEditorGadgets();
1320 strcpy(level_editor_gadget[ED_CTRL_ID_LEVEL_NAME]->text.value, level.name);
1322 MapControlButtons();
1325 MapMainDrawingArea();
1328 DrawDrawingWindow();
1332 OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
1336 void DrawControlWindow()
1341 UnmapLevelEditorWindowGadgets();
1343 /* Inhalt der Mampfer */
1344 DrawText(ED_COUNT_GADGET_XPOS+1,SY+6,
1345 "Contents of a smashed cruncher:",FS_SMALL,FC_YELLOW);
1346 for(i=0;i<4;i++) for(y=0;y<4;y++) for(x=0;x<4;x++)
1348 DrawMiniElement(1+5*i+x,2+y,EL_ERDREICH);
1349 XFillRectangle(display,drawto,gc,
1350 SX+(1+5*i)*MINI_TILEX+MINI_TILEX/2-1,
1351 SY+(2)*MINI_TILEY+MINI_TILEY/2-1,
1352 3*MINI_TILEX+2,3*MINI_TILEY+2);
1354 XCopyArea(display,drawto,drawto,gc,
1355 SX+1*MINI_TILEX,SY+2*MINI_TILEY,
1356 4*5*MINI_TILEX,5*MINI_TILEY,
1357 SX+1*MINI_TILEX-MINI_TILEX/2,SY+2*MINI_TILEY-MINI_TILEY/2);
1360 for(y=0;y<3;y++) for(x=0;x<3;x++)
1361 DrawMiniElement(1+5*i+x,2+y,level.mampfer_inhalt[i][x][y]);
1363 DrawText(SX+MINI_TILEX+(5*i+1)*MINI_TILEX+1,
1364 SY+2*MINI_TILEY+(4)*MINI_TILEY-4,
1365 int2str(i+1,1),FS_SMALL,FC_YELLOW);
1368 /* Inhalt der Amöbe */
1369 for(y=0;y<2;y++) for(x=0;x<2;x++)
1371 DrawMiniElement(29+x,26+y,EL_ERDREICH);
1372 XFillRectangle(display,drawto,gc,
1373 SX+29*MINI_TILEX+MINI_TILEX/2-1,
1374 SY+26*MINI_TILEY+MINI_TILEY/2-1,
1375 MINI_TILEX+2,MINI_TILEY+2);
1377 XCopyArea(display,drawto,drawto,gc,
1378 SX+29*MINI_TILEX,SY+26*MINI_TILEY,
1379 3*MINI_TILEX,3*MINI_TILEY,
1380 SX+29*MINI_TILEX-MINI_TILEX/2,SY+26*MINI_TILEY-MINI_TILEY/2);
1381 DrawMiniElement(29,26,level.amoebe_inhalt);
1383 for(i=0;i<11+3+2;i++)
1385 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1386 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1387 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1388 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1389 ED_COUNT_GADGET_XPOS,
1390 ED_COUNT_GADGET_YPOS+i*ED_COUNT_GADGET_YSIZE);
1393 DrawText(ED_COUNT_VALUE_XPOS,
1394 ED_COUNT_VALUE_YPOS+i*ED_COUNT_GADGET_YSIZE,
1395 int2str(level.score[i],3),FS_SMALL,FC_YELLOW);
1397 DrawText(ED_COUNT_VALUE_XPOS,
1398 ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1399 int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1401 DrawText(ED_COUNT_VALUE_XPOS,
1402 ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1403 int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1405 DrawText(ED_COUNT_VALUE_XPOS,
1406 ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1407 int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1409 DrawText(ED_COUNT_VALUE_XPOS,
1410 ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1411 int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1413 DrawText(ED_COUNT_VALUE_XPOS,
1414 ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1415 int2str(level.time,3),FS_SMALL,FC_YELLOW);
1418 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+0*ED_COUNT_TEXT_YSIZE,
1419 "Score for Emerald",FS_SMALL,FC_YELLOW);
1420 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+1*ED_COUNT_TEXT_YSIZE,
1421 "Score for Diamond",FS_SMALL,FC_YELLOW);
1422 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+2*ED_COUNT_TEXT_YSIZE,
1423 "Score for smashing a Bug",FS_SMALL,FC_YELLOW);
1424 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+3*ED_COUNT_TEXT_YSIZE,
1425 "Score for smashing a Spaceship",FS_SMALL,FC_YELLOW);
1426 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+4*ED_COUNT_TEXT_YSIZE,
1427 "Score for smashing a Cruncher",FS_SMALL,FC_YELLOW);
1428 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+5*ED_COUNT_TEXT_YSIZE,
1429 "Score for smashing an Alien",FS_SMALL,FC_YELLOW);
1430 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+6*ED_COUNT_TEXT_YSIZE,
1431 "Score for smashing a Pacman",FS_SMALL,FC_YELLOW);
1432 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+7*ED_COUNT_TEXT_YSIZE,
1433 "Score for cracking a nut",FS_SMALL,FC_YELLOW);
1434 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+8*ED_COUNT_TEXT_YSIZE,
1435 "Score for dynamite",FS_SMALL,FC_YELLOW);
1436 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+9*ED_COUNT_TEXT_YSIZE,
1437 "Score for key",FS_SMALL,FC_YELLOW);
1438 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+10*ED_COUNT_TEXT_YSIZE,
1439 "Score for each 10 seconds left",FS_SMALL,FC_YELLOW);
1440 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+11*ED_COUNT_TEXT_YSIZE,
1441 "Speed of the amoeba / Content",FS_SMALL,FC_YELLOW);
1442 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+12*ED_COUNT_TEXT_YSIZE,
1443 "Time for magic wall",FS_SMALL,FC_YELLOW);
1444 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+13*ED_COUNT_TEXT_YSIZE,
1445 "Time for wheel",FS_SMALL,FC_YELLOW);
1446 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+14*ED_COUNT_TEXT_YSIZE,
1447 "Emeralds needed in this level",FS_SMALL,FC_YELLOW);
1448 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+15*ED_COUNT_TEXT_YSIZE,
1449 "Time available for this level",FS_SMALL,FC_YELLOW);
1451 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1452 DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS,
1453 DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1454 ED_WIN_COUNT_XSIZE,ED_WIN_COUNT_YSIZE,
1455 ED_COUNT_GADGET_XPOS,
1456 ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1458 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1459 DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS+3+2*FONT2_XSIZE,
1460 DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1461 ED_WIN_COUNT_XSIZE-3-2*FONT2_XSIZE,ED_WIN_COUNT_YSIZE,
1462 ED_COUNT_GADGET_XPOS+3+i*FONT2_XSIZE,
1463 ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1464 DrawText(ED_COUNT_GADGET_XPOS+5,
1465 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1466 level.name,FS_SMALL,FC_YELLOW);
1467 DrawText(ED_COUNT_GADGET_XPOS+(30+3)*FONT2_XSIZE-5,
1468 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1469 "Title",FS_SMALL,FC_YELLOW);
1471 DrawText(ED_SIZE_GADGET_XPOS,ED_SIZE_GADGET_YPOS-18,
1472 "Playfield size:",FS_SMALL,FC_YELLOW);
1473 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1474 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1475 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1476 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1477 ED_SIZE_GADGET_XPOS,
1478 ED_SIZE_GADGET_YPOS+0*ED_COUNT_GADGET_YSIZE);
1479 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1480 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1481 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1482 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1483 ED_SIZE_GADGET_XPOS,
1484 ED_SIZE_GADGET_YPOS+1*ED_COUNT_GADGET_YSIZE);
1485 DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+0*ED_SIZE_TEXT_YSIZE,
1486 "Width",FS_SMALL,FC_YELLOW);
1487 DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+1*ED_SIZE_TEXT_YSIZE,
1488 "Height",FS_SMALL,FC_YELLOW);
1489 DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1490 int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1491 DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1492 int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1495 void AdjustLevelScrollPosition()
1497 if (level_xpos < -1)
1499 if (level_xpos > lev_fieldx - ED_FIELDX + 1)
1500 level_xpos = lev_fieldx - ED_FIELDX + 1;
1501 if (lev_fieldx < ED_FIELDX - 2)
1504 if (level_ypos < -1)
1506 if (level_ypos > lev_fieldy - ED_FIELDY + 1)
1507 level_ypos = lev_fieldy - ED_FIELDY + 1;
1508 if (lev_fieldy < ED_FIELDY - 2)
1512 void AdjustEditorScrollbar(int id)
1514 struct GadgetInfo *gi = level_editor_gadget[id];
1515 int items_max, items_visible, item_position;
1517 if (id == ED_CTRL_ID_SCROLL_HORIZONTAL)
1519 items_max = lev_fieldx + 2;
1520 items_visible = ED_FIELDX;
1521 item_position = level_xpos + 1;
1525 items_max = lev_fieldy + 2;
1526 items_visible = ED_FIELDY;
1527 item_position = level_ypos + 1;
1530 if (item_position > items_max - items_visible)
1531 item_position = items_max - items_visible;
1533 AdjustScrollbar(gi, items_max, item_position);
1536 void ModifyEditorTextInput(int gadget_id, char *new_text)
1538 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1540 ModifyTextInputTextValue(gi, new_text);
1543 void ModifyEditorCounter(int counter_id, int new_value)
1545 int *counter_value = *counterbutton_info[counter_id].counter_value;
1546 int gadget_id = counterbutton_info[counter_id].gadget_id_text;
1547 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1549 ModifyTextInputNumberValue(gi, new_value);
1551 if (counter_value != NULL)
1552 *counter_value = gi->text.number_value;
1555 static void PickDrawingElement(int button, int element)
1557 if (button < 1 || button > 3)
1562 new_element1 = element;
1563 DrawMiniGraphicExt(drawto, gc,
1564 DX + ED_WIN_MB_LEFT_XPOS,
1565 DY + ED_WIN_MB_LEFT_YPOS,
1566 el2gfx(new_element1));
1568 else if (button == 2)
1570 new_element2 = element;
1571 DrawMiniGraphicExt(drawto, gc,
1572 DX + ED_WIN_MB_MIDDLE_XPOS,
1573 DY + ED_WIN_MB_MIDDLE_YPOS,
1574 el2gfx(new_element2));
1578 new_element3 = element;
1579 DrawMiniGraphicExt(drawto, gc,
1580 DX + ED_WIN_MB_RIGHT_XPOS,
1581 DY + ED_WIN_MB_RIGHT_YPOS,
1582 el2gfx(new_element3));
1585 redraw_mask |= REDRAW_DOOR_1;
1588 void LevelEd(int mx, int my, int button)
1590 static int last_button = 0;
1591 static int in_field_pressed = FALSE;
1592 static boolean use_floodfill = FALSE;
1596 int x = (mx-SX)/MINI_TILEX;
1597 int y = (my-SY)/MINI_TILEY;
1601 HandlePressedControlButtons();
1602 HandleDrawingFunctions(mx, my, button);
1605 if (use_floodfill) /********** FLOOD FILL **********/
1613 if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
1618 if (x>lev_fieldx || y>lev_fieldy ||
1619 (x==0 && level_xpos<0) ||
1620 (x==ED_FIELDX-1 && level_xpos>lev_fieldx-ED_FIELDX) ||
1621 (y==0 && level_ypos<0) ||
1622 (y==ED_FIELDY-1 && level_ypos>lev_fieldy-ED_FIELDY))
1625 from_x = x+level_xpos;
1626 from_y = y+level_ypos;
1627 fill_element = (button==1 ? new_element1 :
1628 button==2 ? new_element2 :
1629 button==3 ? new_element3 : 0);
1631 FloodFill(from_x,from_y,fill_element);
1632 DrawMiniLevel(level_xpos,level_ypos);
1635 use_floodfill = FALSE;
1636 CloseDoor(DOOR_CLOSE_1);
1637 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
1646 else /********** EDIT/CTRL-FENSTER **********/
1648 static unsigned long choice_delay = 0;
1649 int choice = CheckElemButtons(mx,my,button);
1650 int elem_pos = choice-ED_BUTTON_ELEM;
1652 if (((choice == ED_BUTTON_EUP && element_shift>0) ||
1653 (choice == ED_BUTTON_EDOWN &&
1654 element_shift<elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)) &&
1655 DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1657 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
1661 step = (button==1 ? MAX_ELEM_X : button==2 ? 5*MAX_ELEM_X :
1663 element_shift += (choice==ED_BUTTON_EUP ? -step : step);
1665 step = step * MAX_ELEM_X * (choice == ED_BUTTON_EUP ? -1 : +1);
1666 element_shift += step;
1669 if (element_shift<0)
1671 if (element_shift>elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)
1672 element_shift = elements_in_list-MAX_ELEM_X*MAX_ELEM_Y;
1673 if (element_shift % MAX_ELEM_X)
1674 element_shift += MAX_ELEM_X-(element_shift % MAX_ELEM_X);
1676 for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1677 DrawElemButton(i+2,ED_BUTTON_RELEASED);
1679 else if (elem_pos>=0 && elem_pos<MAX_ELEM_X*MAX_ELEM_Y)
1683 if (elem_pos+element_shift < elements_in_list)
1684 new_element = editor_element[elem_pos+element_shift];
1686 new_element = EL_LEERRAUM;
1688 PickDrawingElement(last_button, new_element);
1690 if (!HAS_CONTENT(properties_element))
1692 properties_element = new_element;
1693 if (edit_mode == ED_MODE_PROPERTIES)
1694 DrawPropertiesWindow();
1698 if (edit_mode == ED_MODE_DRAWING) /********** EDIT-FENSTER **********/
1705 switch(CheckEditButtons(mx,my,button))
1707 case ED_BUTTON_CTRL:
1708 CloseDoor(DOOR_CLOSE_2);
1709 DrawControlWindow();
1710 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1711 DOOR_GFX_PAGEX4,DOOR_GFX_PAGEY1+80,
1713 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1714 OpenDoor(DOOR_OPEN_2);
1715 edit_mode = ED_MODE_INFO;
1717 case ED_BUTTON_FILL:
1718 Request("Caution ! Flood fill mode ! Choose area !",REQ_OPEN);
1719 use_floodfill = TRUE;
1722 case ED_BUTTON_LEFT:
1725 if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1727 if (lev_fieldx<ED_FIELDX-2)
1730 level_xpos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
1734 ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_RIGHT);
1736 DrawMiniLevel(level_xpos,level_ypos);
1739 case ED_BUTTON_RIGHT:
1740 if (level_xpos<=lev_fieldx-ED_FIELDX)
1742 if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1744 if (lev_fieldx<ED_FIELDX-2)
1747 level_xpos += (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
1748 if (level_xpos>lev_fieldx-ED_FIELDX+1)
1749 level_xpos = lev_fieldx-ED_FIELDX+1;
1751 ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_LEFT);
1753 DrawMiniLevel(level_xpos,level_ypos);
1759 if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1761 if (lev_fieldy<ED_FIELDY-2)
1764 level_ypos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
1768 ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_DOWN);
1770 DrawMiniLevel(level_xpos,level_ypos);
1773 case ED_BUTTON_DOWN:
1774 if (level_ypos<=lev_fieldy-ED_FIELDY)
1776 if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1778 if (lev_fieldy<ED_FIELDY-2)
1781 level_ypos += (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
1782 if (level_ypos>lev_fieldy-ED_FIELDY+1)
1783 level_ypos = lev_fieldy-ED_FIELDY+1;
1785 ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_UP);
1787 DrawMiniLevel(level_xpos,level_ypos);
1800 if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
1804 if (button && !motion_status)
1805 in_field_pressed = TRUE;
1807 if (!button || !in_field_pressed || button<1 || button>3 ||
1808 (y==0 && level_ypos<0) ||
1809 (y==ED_FIELDY-1 && level_ypos>lev_fieldy-ED_FIELDY) ||
1810 (x==0 && level_xpos<0) ||
1811 (x==ED_FIELDX-1 && level_xpos>lev_fieldx-ED_FIELDX) ||
1812 x>lev_fieldx || y>lev_fieldy)
1815 new_element = (button==1 ? new_element1 :
1816 button==2 ? new_element2 :
1817 button==3 ? new_element3 : 0);
1819 if (new_element != Feld[x+level_xpos][y+level_ypos])
1821 if (new_element==EL_SPIELFIGUR) /* Jeder nur EINE Figur bitte... */
1825 for(x=0;x<lev_fieldx;x++) for(y=0;y<lev_fieldy;y++)
1827 if (Feld[x][y]==EL_SPIELFIGUR || Feld[x][y]==EL_SPIELER1)
1829 Feld[x][y] = EL_LEERRAUM;
1830 if (x-level_xpos>=0 && x-level_xpos<ED_FIELDX &&
1831 y-level_ypos>=0 && y-level_ypos<ED_FIELDY)
1832 DrawMiniElement(x-level_xpos,y-level_ypos,EL_LEERRAUM);
1837 Feld[x+level_xpos][y+level_ypos] = new_element;
1838 DrawMiniElement(x,y,new_element);
1841 else if (!motion_status) /* Mauszeiger nicht im Level-Feld */
1842 in_field_pressed = FALSE;
1849 else if (edit_mode == ED_MODE_INFO)/********** KONTROLL-FENSTER **********/
1851 int choice = CheckCountButtons(mx,my,button);
1852 int step = (button==1 ? 1 : button==2 ? 5 : button==3 ? 10 : 0);
1854 if (choice >= 0 && choice < 36 &&
1855 DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1864 level.score[choice] += step;
1865 if (level.score[choice]<0)
1866 level.score[choice] = 0;
1867 else if (level.score[choice]>255)
1868 level.score[choice] = 255;
1870 else if (choice==11)
1872 level.tempo_amoebe += step;
1873 if (level.tempo_amoebe<0)
1874 level.tempo_amoebe = 0;
1875 else if (level.tempo_amoebe>255)
1876 level.tempo_amoebe = 255;
1878 else if (choice==12)
1880 level.dauer_sieb += step;
1881 if (level.dauer_sieb<0)
1882 level.dauer_sieb = 0;
1883 else if (level.dauer_sieb>255)
1884 level.dauer_sieb = 255;
1886 else if (choice==13)
1888 level.dauer_ablenk += step;
1889 if (level.dauer_ablenk<0)
1890 level.dauer_ablenk = 0;
1891 else if (level.dauer_ablenk>255)
1892 level.dauer_ablenk = 255;
1894 else if (choice==14)
1896 level.edelsteine += step;
1897 if (level.edelsteine<0)
1898 level.edelsteine = 0;
1899 else if (level.edelsteine>999)
1900 level.edelsteine = 999;
1902 else if (choice==15)
1907 else if (level.time>999)
1910 else if (choice==16)
1913 if (lev_fieldx<MIN_LEV_FIELDX)
1914 lev_fieldx = MIN_LEV_FIELDX;
1915 else if (lev_fieldx>MAX_LEV_FIELDX)
1916 lev_fieldx = MAX_LEV_FIELDX;
1917 level.fieldx = lev_fieldx;
1919 else if (choice==17)
1922 if (lev_fieldy<MIN_LEV_FIELDY)
1923 lev_fieldy = MIN_LEV_FIELDY;
1924 else if (lev_fieldy>MAX_LEV_FIELDY)
1925 lev_fieldy = MAX_LEV_FIELDY;
1926 level.fieldy = lev_fieldy;
1930 DrawText(ED_COUNT_VALUE_XPOS,
1931 ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
1932 int2str(level.score[choice],3),FS_SMALL,FC_YELLOW);
1933 else if (choice==11)
1934 DrawText(ED_COUNT_VALUE_XPOS,
1935 ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1936 int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1937 else if (choice==12)
1938 DrawText(ED_COUNT_VALUE_XPOS,
1939 ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1940 int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1941 else if (choice==13)
1942 DrawText(ED_COUNT_VALUE_XPOS,
1943 ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1944 int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1945 else if (choice==14)
1946 DrawText(ED_COUNT_VALUE_XPOS,
1947 ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1948 int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1949 else if (choice==15)
1950 DrawText(ED_COUNT_VALUE_XPOS,
1951 ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1952 int2str(level.time,3),FS_SMALL,FC_YELLOW);
1953 else if (choice==16)
1954 DrawText(ED_SIZE_VALUE_XPOS,
1955 ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1956 int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1957 else if (choice==17)
1958 DrawText(ED_SIZE_VALUE_XPOS,
1959 ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1960 int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1962 redraw_mask &= ~REDRAW_FIELD;
1964 XCopyArea(display,drawto,window,gc,
1965 ED_COUNT_VALUE_XPOS,
1966 ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
1967 3*FONT2_XSIZE,FONT2_YSIZE,
1968 ED_COUNT_VALUE_XPOS,
1969 ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE);
1971 XCopyArea(display,drawto,window,gc,
1973 ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE,
1974 3*FONT2_XSIZE,FONT2_YSIZE,
1976 ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE);
1984 switch(CheckCtrlButtons(mx,my,button))
1986 case ED_BUTTON_EDIT:
1987 CloseDoor(DOOR_CLOSE_2);
1988 AdjustLevelScrollPosition();
1989 DrawMiniLevel(level_xpos,level_ypos);
1990 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1991 DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1993 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1994 OpenDoor(DOOR_OPEN_2);
1995 edit_mode = ED_MODE_DRAWING;
1997 case ED_BUTTON_CLEAR:
1998 if (Request("Are you sure to clear this level ?",REQ_ASK))
2000 for(x=0;x<MAX_LEV_FIELDX;x++)
2001 for(y=0;y<MAX_LEV_FIELDY;y++)
2002 Feld[x][y] = EL_ERDREICH;
2003 DrawMiniLevel(level_xpos,level_ypos);
2006 case ED_BUTTON_UNDO:
2007 if (leveldir[leveldir_nr].readonly ||
2008 Request("Exit without saving ?",REQ_ASK | REQ_STAY_OPEN))
2010 CloseDoor(DOOR_CLOSE_ALL);
2011 game_status=MAINMENU;
2016 CloseDoor(DOOR_CLOSE_1);
2017 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2020 case ED_BUTTON_EXIT:
2022 int figur_vorhanden = FALSE;
2024 if (leveldir[leveldir_nr].readonly)
2026 Request("This level is read only !",REQ_CONFIRM);
2030 for(y=0;y<lev_fieldy;y++)
2031 for(x=0;x<lev_fieldx;x++)
2032 if (Feld[x][y] == EL_SPIELFIGUR ||
2033 Feld[x][y] == EL_SPIELER1 ||
2034 Feld[x][y] == EL_SP_MURPHY)
2035 figur_vorhanden = TRUE;
2037 if (!figur_vorhanden)
2038 Request("No Level without Gregor Mc Duffin please !",
2042 if (Request("Save this level and kill the old ?",
2043 REQ_ASK | REQ_STAY_OPEN))
2045 for(x=0;x<lev_fieldx;x++)
2046 for(y=0;y<lev_fieldy;y++)
2047 Ur[x][y]=Feld[x][y];
2048 SaveLevel(level_nr);
2050 CloseDoor(DOOR_CLOSE_ALL);
2051 game_status=MAINMENU;
2064 if (mx>=ED_COUNT_GADGET_XPOS &&
2065 mx<ED_COUNT_GADGET_XPOS+31*FONT2_XSIZE+10 &&
2066 my>=ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE &&
2067 my<ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE+ED_WIN_COUNT_YSIZE)
2072 DrawText(ED_COUNT_GADGET_XPOS+5,
2073 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2074 level.name,FS_SMALL,FC_GREEN);
2075 DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
2076 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2077 "<",FS_SMALL,FC_RED);
2084 name_typing = FALSE;
2085 DrawText(ED_COUNT_GADGET_XPOS+5,
2086 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2087 level.name,FS_SMALL,FC_YELLOW);
2088 DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
2089 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2090 " ",FS_SMALL,FC_RED);
2094 if (mx>=SX+29*MINI_TILEX && mx<SX+30*MINI_TILEX &&
2095 my>=SY+26*MINI_TILEY && my<SY+27*MINI_TILEY)
2099 if (!button || button<1 || button>3)
2102 new_element = (button==1 ? new_element1 :
2103 button==2 ? new_element2 :
2104 button==3 ? new_element3 : 0);
2106 if (new_element != level.amoebe_inhalt)
2108 level.amoebe_inhalt = new_element;
2109 DrawMiniElement(29,26,new_element);
2113 if (mx>=SX+1*MINI_TILEX && mx<SX+(1+4*5)*MINI_TILEX &&
2114 my>=SY+2*MINI_TILEY && my<SY+(2+3)*MINI_TILEY)
2116 int x = (mx-SX-1*MINI_TILEX)/MINI_TILEX;
2117 int y = (my-SY-2*MINI_TILEY)/MINI_TILEY;
2122 if (i>=0 && i<43 && x>=0 && x<3 && y>=0 && y<3)
2124 if (button && !motion_status)
2125 in_field_pressed = TRUE;
2127 if (!button || !in_field_pressed || button<1 || button>3)
2130 new_element = (button==1 ? new_element1 :
2131 button==2 ? new_element2 :
2132 button==3 ? new_element3 : 0);
2134 if (new_element != level.mampfer_inhalt[i][x][y])
2136 level.mampfer_inhalt[i][x][y] = new_element;
2137 DrawMiniElement(1+5*i+x,2+y,new_element);
2140 else if (!motion_status)/* Mauszeiger nicht im Cruncher-Feld */
2141 in_field_pressed = FALSE;
2143 else if (!motion_status) /* Mauszeiger nicht im Cruncher-Feld */
2144 in_field_pressed = FALSE;
2148 last_button = button;
2153 void LevelNameTyping(KeySym key)
2155 unsigned char ascii = 0;
2156 int len = strlen(level.name);
2161 if (key>=XK_A && key<=XK_Z)
2162 ascii = 'A'+(char)(key-XK_A);
2163 else if (key>=XK_a && key<=XK_z)
2164 ascii = 'a'+(char)(key-XK_a);
2165 else if (key>=XK_0 && key<=XK_9)
2166 ascii = '0'+(char)(key-XK_0);
2168 else if (key>=XK_space && key<=XK_at)
2169 ascii = ' '+(char)(key-XK_space);
2170 else if (key==XK_Adiaeresis)
2172 else if (key==XK_Odiaeresis)
2174 else if (key==XK_Udiaeresis)
2176 else if (key==XK_adiaeresis)
2178 else if (key==XK_odiaeresis)
2180 else if (key==XK_udiaeresis)
2182 else if (key==XK_underscore)
2186 if (ascii && len<MAX_LEVNAMLEN-2)
2188 level.name[len] = ascii;
2189 level.name[len+1] = 0;
2192 DrawTextExt(drawto,gc,
2193 ED_COUNT_GADGET_XPOS+5,
2194 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2195 level.name,FS_SMALL,FC_GREEN);
2196 DrawTextExt(window,gc,
2197 ED_COUNT_GADGET_XPOS+5,
2198 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2199 level.name,FS_SMALL,FC_GREEN);
2200 DrawTextExt(drawto,gc,
2201 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2202 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2203 "<",FS_SMALL,FC_RED);
2204 DrawTextExt(window,gc,
2205 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2206 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2207 "<",FS_SMALL,FC_RED);
2209 else if ((key==XK_Delete || key==XK_BackSpace) && len>0)
2211 level.name[len-1] = 0;
2214 DrawTextExt(drawto,gc,
2215 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2216 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2217 "< ",FS_SMALL,FC_GREEN);
2218 DrawTextExt(window,gc,
2219 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2220 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2221 "< ",FS_SMALL,FC_GREEN);
2223 else if (key==XK_Return)
2225 DrawTextExt(drawto,gc,
2226 ED_COUNT_GADGET_XPOS+5,
2227 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2228 level.name,FS_SMALL,FC_YELLOW);
2229 DrawTextExt(window,gc,
2230 ED_COUNT_GADGET_XPOS+5,
2231 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2232 level.name,FS_SMALL,FC_YELLOW);
2233 DrawTextExt(drawto,gc,
2234 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2235 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2236 " ",FS_SMALL,FC_YELLOW);
2237 DrawTextExt(window,gc,
2238 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2239 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2240 " ",FS_SMALL,FC_YELLOW);
2242 name_typing = FALSE;
2246 static void DrawCounterValueField(int counter_id, int value)
2248 int x = SX + counterbutton_info[counter_id].x + ED_WIN_COUNT_XPOS;
2249 int y = SY + counterbutton_info[counter_id].y;
2251 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2252 DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS,
2253 DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS,
2254 ED_WIN_COUNT_XSIZE, ED_WIN_COUNT_YSIZE,
2257 DrawText(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2258 int2str(value, 3), FS_SMALL, FC_YELLOW);
2261 static void DrawDrawingWindow()
2264 UnmapLevelEditorWindowGadgets();
2265 AdjustLevelScrollPosition();
2266 AdjustEditorScrollbar(ED_CTRL_ID_SCROLL_HORIZONTAL);
2267 AdjustEditorScrollbar(ED_CTRL_ID_SCROLL_VERTICAL);
2268 DrawMiniLevel(level_xpos, level_ypos);
2269 MapMainDrawingArea();
2272 static void DrawElementContentAreas()
2274 int *num_areas = &MampferMax;
2275 int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX;
2276 int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY;
2277 int area_sx = SX + ED_AREA_ELEMCONT_XPOS;
2278 int area_sy = SY + ED_AREA_ELEMCONT_YPOS;
2281 for (i=0; i<MAX_ELEMCONT; i++)
2284 ElementContent[i][x][y] = level.mampfer_inhalt[i][x][y];
2286 for (i=0; i<MAX_ELEMCONT; i++)
2287 UnmapDrawingArea(ED_CTRL_ID_ELEMCONT_0 + i);
2289 /* display counter to choose number of element content areas */
2290 gadget_areas_value = num_areas;
2291 DrawCounterValueField(ED_COUNTER_ID_ELEMCONT, *gadget_areas_value);
2292 x = counterbutton_info[ED_COUNTER_ID_ELEMCONT].x + DXSIZE;
2293 y = counterbutton_info[ED_COUNTER_ID_ELEMCONT].y;
2294 DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2295 FC_YELLOW, "number of content areas");
2296 ModifyEditorCounter(ED_COUNTER_ID_ELEMCONT, *gadget_areas_value);
2297 MapCounterButtons(ED_COUNTER_ID_ELEMCONT);
2299 /* delete content areas in case of reducing number of them */
2300 XFillRectangle(display, backbuffer, gc,
2301 SX, area_sy - MINI_TILEX,
2302 SXSIZE, 12 * MINI_TILEY);
2304 /* draw some decorative border for the objects */
2305 for (i=0; i<*num_areas; i++)
2309 DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2312 XFillRectangle(display, drawto, gc,
2313 area_sx + 5 * (i % 4) * MINI_TILEX + MINI_TILEX/2 - 1,
2314 area_sy + 6 * (i / 4) * MINI_TILEY + MINI_TILEY/2 - 1,
2315 3 * MINI_TILEX + 2, 3 * MINI_TILEY + 2);
2318 /* copy border to the right location */
2319 XCopyArea(display, drawto, drawto, gc,
2320 area_sx, area_sy, (5 * 4 + 1) * MINI_TILEX, 12 * MINI_TILEY,
2321 area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2323 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
2324 "Content", FS_SMALL, FC_YELLOW);
2325 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
2326 "when", FS_SMALL, FC_YELLOW);
2327 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
2328 "smashed", FS_SMALL, FC_YELLOW);
2330 for (i=0; i<*num_areas; i++)
2334 DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2335 ElementContent[i][x][y]);
2337 DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
2338 area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
2339 FC_YELLOW, "%d", i + 1);
2342 for (i=0; i<*num_areas; i++)
2343 MapDrawingArea(ED_CTRL_ID_ELEMCONT_0 + i);
2346 static void DrawAmoebaContentArea()
2348 int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX;
2349 int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY;
2350 int area_sx = SX + ED_AREA_ELEMCONT_XPOS;
2351 int area_sy = SY + ED_AREA_ELEMCONT_YPOS;
2354 ElementContent[0][0][0] = level.amoebe_inhalt;
2356 /* draw decorative border for the object */
2359 DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
2361 XFillRectangle(display, drawto, gc,
2362 area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
2363 MINI_TILEX + 2, MINI_TILEY + 2);
2365 /* copy border to the right location */
2366 XCopyArea(display, drawto, drawto, gc,
2367 area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
2368 area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2370 DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba",
2371 FS_SMALL, FC_YELLOW);
2373 DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
2375 MapDrawingArea(ED_CTRL_ID_AMOEBA_CONTENT);
2378 #define TEXT_COLLECTING "Score for collecting"
2379 #define TEXT_SMASHING "Score for smashing"
2380 #define TEXT_CRACKING "Score for cracking"
2381 #define TEXT_SPEED "Speed of amoeba growth"
2382 #define TEXT_DURATION "Duration when activated"
2384 static void DrawPropertiesWindow()
2387 int num_elements_in_level;
2393 } elements_with_counter[] =
2395 { EL_EDELSTEIN, &level.score[0], TEXT_COLLECTING },
2396 { EL_EDELSTEIN_BD, &level.score[0], TEXT_COLLECTING },
2397 { EL_EDELSTEIN_GELB,&level.score[0], TEXT_COLLECTING },
2398 { EL_EDELSTEIN_ROT, &level.score[0], TEXT_COLLECTING },
2399 { EL_EDELSTEIN_LILA,&level.score[0], TEXT_COLLECTING },
2400 { EL_DIAMANT, &level.score[1], TEXT_COLLECTING },
2401 { EL_KAEFER_R, &level.score[2], TEXT_SMASHING },
2402 { EL_KAEFER_O, &level.score[2], TEXT_SMASHING },
2403 { EL_KAEFER_L, &level.score[2], TEXT_SMASHING },
2404 { EL_KAEFER_U, &level.score[2], TEXT_SMASHING },
2405 { EL_BUTTERFLY_R, &level.score[2], TEXT_SMASHING },
2406 { EL_BUTTERFLY_O, &level.score[2], TEXT_SMASHING },
2407 { EL_BUTTERFLY_L, &level.score[2], TEXT_SMASHING },
2408 { EL_BUTTERFLY_U, &level.score[2], TEXT_SMASHING },
2409 { EL_FLIEGER_R, &level.score[3], TEXT_SMASHING },
2410 { EL_FLIEGER_O, &level.score[3], TEXT_SMASHING },
2411 { EL_FLIEGER_L, &level.score[3], TEXT_SMASHING },
2412 { EL_FLIEGER_U, &level.score[3], TEXT_SMASHING },
2413 { EL_FIREFLY_R, &level.score[3], TEXT_SMASHING },
2414 { EL_FIREFLY_O, &level.score[3], TEXT_SMASHING },
2415 { EL_FIREFLY_L, &level.score[3], TEXT_SMASHING },
2416 { EL_FIREFLY_U, &level.score[3], TEXT_SMASHING },
2417 { EL_MAMPFER, &level.score[4], TEXT_SMASHING },
2418 { EL_MAMPFER2, &level.score[4], TEXT_SMASHING },
2419 { EL_ROBOT, &level.score[5], TEXT_SMASHING },
2420 { EL_PACMAN_R, &level.score[6], TEXT_SMASHING },
2421 { EL_PACMAN_O, &level.score[6], TEXT_SMASHING },
2422 { EL_PACMAN_L, &level.score[6], TEXT_SMASHING },
2423 { EL_PACMAN_U, &level.score[6], TEXT_SMASHING },
2424 { EL_KOKOSNUSS, &level.score[7], TEXT_CRACKING },
2425 { EL_DYNAMIT_AUS, &level.score[8], TEXT_COLLECTING },
2426 { EL_SCHLUESSEL1, &level.score[9], TEXT_COLLECTING },
2427 { EL_SCHLUESSEL2, &level.score[9], TEXT_COLLECTING },
2428 { EL_SCHLUESSEL3, &level.score[9], TEXT_COLLECTING },
2429 { EL_SCHLUESSEL4, &level.score[9], TEXT_COLLECTING },
2430 { EL_AMOEBE_NASS, &level.tempo_amoebe, TEXT_SPEED },
2431 { EL_AMOEBE_NORM, &level.tempo_amoebe, TEXT_SPEED },
2432 { EL_AMOEBE_VOLL, &level.tempo_amoebe, TEXT_SPEED },
2433 { EL_AMOEBE_BD, &level.tempo_amoebe, TEXT_SPEED },
2434 { EL_SIEB_INAKTIV, &level.dauer_sieb, TEXT_DURATION },
2435 { EL_ABLENK_AUS, &level.dauer_ablenk, TEXT_DURATION },
2440 UnmapLevelEditorWindowGadgets();
2442 /* draw some decorative border for the object */
2445 DrawMiniElement(2 + x , 2 + y, EL_ERDREICH);
2447 XFillRectangle(display, drawto, gc,
2448 SX + TILEX + MINI_TILEX/2 - 1,
2449 SY + TILEY + MINI_TILEY/2 - 1,
2450 TILEX + 2, TILEY + 2);
2452 /* copy border to the right location */
2453 XCopyArea(display, drawto, drawto, gc,
2454 SX + TILEX, SY + TILEY,
2455 2 * TILEX, 2 * TILEY,
2456 SX + TILEX - MINI_TILEX/2, SY + TILEY - MINI_TILEY/2);
2458 DrawGraphic(1, 1, el2gfx(properties_element));
2459 DrawText(SX + 3*TILEX, SY + 5*TILEY/4, "Element Properties",
2460 FS_SMALL, FC_YELLOW);
2462 num_elements_in_level = 0;
2463 for (y=0; y<lev_fieldy; y++)
2464 for (x=0; x<lev_fieldx; x++)
2465 if (Feld[x][y] == properties_element)
2466 num_elements_in_level++;
2468 DrawTextF(ED_PROPERTIES_XPOS, 5*TILEY, FC_YELLOW, "%d x contained in level",
2469 num_elements_in_level);
2471 /* check if there are elements where a score can be chosen for */
2472 for (i=0; elements_with_counter[i].element != -1; i++)
2474 if (elements_with_counter[i].element == properties_element)
2476 int x = counterbutton_info[ED_COUNTER_ID_SCORE].x + DXSIZE;
2477 int y = counterbutton_info[ED_COUNTER_ID_SCORE].y;
2479 gadget_score_value = elements_with_counter[i].counter_value;
2482 DrawCounterValueField(ED_COUNTER_ID_SCORE, *gadget_score_value);
2485 DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2486 FC_YELLOW, elements_with_counter[i].text);
2487 ModifyEditorCounter(ED_COUNTER_ID_SCORE, *gadget_score_value);
2488 MapCounterButtons(ED_COUNTER_ID_SCORE);
2493 if (HAS_CONTENT(properties_element))
2495 if (IS_AMOEBOID(properties_element))
2496 DrawAmoebaContentArea();
2498 DrawElementContentAreas();
2501 /* TEST ONLY: level name text input gadget */
2502 MapTextInputGadget(ED_CTRL_ID_LEVEL_NAME);
2505 static void swap_numbers(int *i1, int *i2)
2513 static void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
2525 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
2527 int lx = sx + level_xpos;
2528 int ly = sy + level_ypos;
2530 DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element));
2533 Feld[lx][ly] = element;
2536 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
2537 int element, boolean change_level)
2539 if (from_y == to_y) /* horizontal line */
2545 swap_numbers(&from_x, &to_x);
2547 for (x=from_x; x<=to_x; x++)
2548 DrawLineElement(x, y, element, change_level);
2550 else if (from_x == to_x) /* vertical line */
2556 swap_numbers(&from_y, &to_y);
2558 for (y=from_y; y<=to_y; y++)
2559 DrawLineElement(x, y, element, change_level);
2561 else /* diagonal line */
2563 int len_x = ABS(to_x - from_x);
2564 int len_y = ABS(to_y - from_y);
2567 if (len_y < len_x) /* a < 1 */
2569 float a = (float)len_y / (float)len_x;
2572 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2574 for (x=0; x<=len_x; x++)
2576 int y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1);
2578 DrawLineElement(from_x + x, from_y + y, element, change_level);
2583 float a = (float)len_x / (float)len_y;
2586 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2588 for (y=0; y<=len_y; y++)
2590 int x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1);
2592 DrawLineElement(from_x + x, from_y + y, element, change_level);
2598 static void DrawRectangle(int from_x, int from_y, int to_x, int to_y,
2599 int element, boolean change_level)
2601 DrawLine(from_x, from_y, from_x, to_y, element, change_level);
2602 DrawLine(from_x, to_y, to_x, to_y, element, change_level);
2603 DrawLine(to_x, to_y, to_x, from_y, element, change_level);
2604 DrawLine(to_x, from_y, from_x, from_y, element, change_level);
2607 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
2608 int element, boolean change_level)
2613 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2615 for (y=from_y; y<=to_y; y++)
2616 DrawLine(from_x, y, to_x, y, element, change_level);
2619 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
2621 int from_sx, from_sy;
2625 swap_numbers(&from_x, &to_x);
2628 swap_numbers(&from_y, &to_y);
2630 from_sx = SX + from_x * MINI_TILEX;
2631 from_sy = SY + from_y * MINI_TILEY;
2632 to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
2633 to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
2635 XSetForeground(display, gc, WhitePixel(display, screen));
2637 XDrawLine(display, drawto, gc, from_sx, from_sy, to_sx, from_sy);
2638 XDrawLine(display, drawto, gc, to_sx, from_sy, to_sx, to_sy);
2639 XDrawLine(display, drawto, gc, to_sx, to_sy, from_sx, to_sy);
2640 XDrawLine(display, drawto, gc, from_sx, to_sy, from_sx, from_sy);
2642 XSetForeground(display, gc, BlackPixel(display, screen));
2644 if (from_x == to_x && from_y == to_y)
2645 MarkTileDirty(from_x/2, from_y/2);
2647 redraw_mask |= REDRAW_FIELD;
2650 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
2651 int element, boolean change_level)
2653 if (element == -1 || change_level)
2654 DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE);
2656 DrawAreaBorder(from_x, from_y, to_x, to_y);
2659 /* values for CopyBrushExt() */
2660 #define CB_AREA_TO_BRUSH 0
2661 #define CB_BRUSH_TO_CURSOR 1
2662 #define CB_BRUSH_TO_LEVEL 2
2663 #define CB_DELETE_OLD_CURSOR 3
2665 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
2666 int button, int mode)
2668 static short brush_buffer[ED_FIELDX][ED_FIELDY];
2669 static int brush_width, brush_height;
2670 static int last_cursor_x = -1, last_cursor_y = -1;
2671 static boolean delete_old_brush;
2675 if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
2678 new_element = (button == 1 ? new_element1 :
2679 button == 2 ? new_element2 :
2680 button == 3 ? new_element3 : 0);
2682 if (mode == CB_AREA_TO_BRUSH)
2684 int from_lx, from_ly;
2687 swap_numbers(&from_x, &to_x);
2690 swap_numbers(&from_y, &to_y);
2692 brush_width = to_x - from_x + 1;
2693 brush_height = to_y - from_y + 1;
2695 from_lx = from_x + level_xpos;
2696 from_ly = from_y + level_ypos;
2698 for (y=0; y<brush_height; y++)
2700 for (x=0; x<brush_width; x++)
2702 brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
2705 DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
2710 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2712 delete_old_brush = FALSE;
2714 else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
2715 mode == CB_BRUSH_TO_LEVEL)
2717 int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x);
2718 int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y);
2719 int cursor_from_x = cursor_x - brush_width / 2;
2720 int cursor_from_y = cursor_y - brush_height / 2;
2721 int border_from_x = cursor_x, border_from_y = cursor_y;
2722 int border_to_x = cursor_x, border_to_y = cursor_y;
2724 if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
2725 CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2727 if (!IN_ED_FIELD(cursor_x, cursor_y) ||
2728 !IN_LEV_FIELD(cursor_x + level_xpos, cursor_y + level_ypos))
2730 delete_old_brush = FALSE;
2734 for (y=0; y<brush_height; y++)
2736 for (x=0; x<brush_width; x++)
2738 int sx = cursor_from_x + x;
2739 int sy = cursor_from_y + y;
2740 int lx = sx + level_xpos;
2741 int ly = sy + level_ypos;
2742 boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
2743 int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
2744 mode == CB_BRUSH_TO_CURSOR || button == 1 ?
2745 brush_buffer[x][y] : new_element);
2747 if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
2749 if (sx < border_from_x)
2751 else if (sx > border_to_x)
2753 if (sy < border_from_y)
2755 else if (sy > border_to_y)
2758 DrawLineElement(sx, sy, element, change_level);
2764 printf("%d, %d - %d, %d in level and screen\n",
2765 border_from_x, border_from_y, border_to_x, border_to_y);
2768 if (mode != CB_DELETE_OLD_CURSOR)
2769 DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
2772 if (mode == CB_BRUSH_TO_LEVEL)
2773 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2776 last_cursor_x = cursor_x;
2777 last_cursor_y = cursor_y;
2778 delete_old_brush = TRUE;
2782 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
2785 CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
2788 static void CopyBrushToLevel(int x, int y, int button)
2790 CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
2793 static void CopyBrushToCursor(int x, int y)
2795 CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
2798 static void DeleteBrushFromCursor()
2800 CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2803 static void FloodFill(int from_x, int from_y, int fill_element)
2807 static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
2808 static int safety = 0;
2810 /* check if starting field still has the desired content */
2811 if (Feld[from_x][from_y] == fill_element)
2816 if (safety > lev_fieldx*lev_fieldy)
2817 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
2819 old_element = Feld[from_x][from_y];
2820 Feld[from_x][from_y] = fill_element;
2824 x = from_x + check[i][0];
2825 y = from_y + check[i][1];
2827 if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element)
2828 FloodFill(x, y, fill_element);
2834 /* values for DrawLevelText() modes */
2836 #define TEXT_SETCURSOR 1
2837 #define TEXT_WRITECHAR 2
2838 #define TEXT_BACKSPACE 3
2839 #define TEXT_NEWLINE 4
2842 static void DrawLevelText(int sx, int sy, char letter, int mode)
2844 static short delete_buffer[MAX_LEV_FIELDX];
2845 static int start_sx, start_sy;
2846 static int last_sx, last_sy;
2847 static boolean typing = FALSE;
2848 int letter_element = EL_CHAR_ASCII0 + letter;
2851 /* map lower case letters to upper case and convert special characters */
2852 if (letter >= 'a' && letter <= 'z')
2853 letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
2854 else if (letter == 'ä' || letter == 'Ä')
2855 letter_element = EL_CHAR_AE;
2856 else if (letter == 'ö' || letter == 'Ö')
2857 letter_element = EL_CHAR_OE;
2858 else if (letter == 'ü' || letter == 'Ü')
2859 letter_element = EL_CHAR_UE;
2860 else if (letter == '^')
2861 letter_element = EL_CHAR_COPY;
2863 letter_element = EL_CHAR_ASCII0 + letter;
2865 if (mode != TEXT_INIT)
2870 if (mode != TEXT_SETCURSOR)
2876 lx = last_sx + level_xpos;
2877 ly = last_sy + level_ypos;
2884 DrawLevelText(0, 0, 0, TEXT_END);
2887 start_sx = last_sx = sx;
2888 start_sy = last_sy = sy;
2889 DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
2892 case TEXT_SETCURSOR:
2893 DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
2894 DrawAreaBorder(sx, sy, sx, sy);
2899 case TEXT_WRITECHAR:
2900 if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
2902 delete_buffer[sx - start_sx] = Feld[lx][ly];
2903 Feld[lx][ly] = letter_element;
2905 if (sx + 1 < ED_FIELDX && lx + 1 < lev_fieldx)
2906 DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
2907 else if (sy + 1 < ED_FIELDY && ly + 1 < lev_fieldy)
2908 DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2910 DrawLevelText(0, 0, 0, TEXT_END);
2914 case TEXT_BACKSPACE:
2917 Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
2918 DrawMiniElement(sx - 1, sy, new_element3);
2919 DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
2924 if (sy + 1 < ED_FIELDY - 1 && ly + 1 < lev_fieldy - 1)
2925 DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2927 DrawLevelText(0, 0, 0, TEXT_END);
2931 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2932 DrawMiniElement(sx, sy, Feld[lx][ly]);
2941 static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
2942 int element, boolean change_level)
2944 int lx = sx + level_xpos;
2945 int ly = sy + level_ypos;
2948 DrawMiniElement(sx, sy, Feld[lx][ly]);
2950 DrawAreaBorder(sx, sy, sx, sy);
2953 static void CopyLevelToUndoBuffer(int mode)
2955 static boolean accumulated_undo = FALSE;
2956 boolean new_undo_buffer_position = TRUE;
2961 case UNDO_IMMEDIATE:
2962 accumulated_undo = FALSE;
2965 case UNDO_ACCUMULATE:
2966 if (accumulated_undo)
2967 new_undo_buffer_position = FALSE;
2968 accumulated_undo = TRUE;
2975 if (new_undo_buffer_position)
2977 /* new position in undo buffer ring */
2978 undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
2980 if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
2981 undo_buffer_steps++;
2984 for(x=0; x<lev_fieldx; x++)
2985 for(y=0; y<lev_fieldy; y++)
2986 UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
2989 printf("level saved to undo buffer\n");
2994 static void RandomPlacement(int button)
2999 new_element = (button == 1 ? new_element1 :
3000 button == 2 ? new_element2 :
3001 button == 3 ? new_element3 : 0);
3003 if (random_placement_method == RANDOM_USE_PERCENTAGE)
3005 for(x=0; x<lev_fieldx; x++)
3006 for(y=0; y<lev_fieldy; y++)
3007 if (RND(100) < random_placement_percentage)
3008 Feld[x][y] = new_element;
3012 int elements_left = random_placement_num_objects;
3014 while (elements_left > 0)
3016 x = RND(lev_fieldx);
3017 y = RND(lev_fieldy);
3019 if (Feld[x][y] != new_element)
3021 Feld[x][y] = new_element;
3027 DrawMiniLevel(level_xpos, level_ypos);
3028 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3031 void WrapLevel(int dx, int dy)
3033 int wrap_dx = lev_fieldx - dx;
3034 int wrap_dy = lev_fieldy - dy;
3037 for(x=0; x<lev_fieldx; x++)
3038 for(y=0; y<lev_fieldy; y++)
3039 FieldBackup[x][y] = Feld[x][y];
3041 for(x=0; x<lev_fieldx; x++)
3042 for(y=0; y<lev_fieldy; y++)
3044 FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
3046 DrawMiniLevel(level_xpos, level_ypos);
3047 CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
3050 static void HandleDrawingAreas(struct GadgetInfo *gi)
3052 static boolean started_inside_drawing_area = FALSE;
3053 int id = gi->custom_id;
3054 boolean inside_drawing_area = !gi->event.off_borders;
3055 boolean button_press_event;
3056 boolean button_release_event;
3057 boolean draw_level = (id == ED_CTRL_ID_DRAWING_LEVEL);
3059 int button = gi->event.button;
3060 int sx = gi->event.x, sy = gi->event.y;
3061 int min_sx = 0, min_sy = 0;
3062 int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
3064 int min_lx = 0, min_ly = 0;
3065 int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
3068 /* handle info callback for each invocation of action callback */
3069 gi->callback_info(gi);
3072 if (edit_mode != ED_MODE_DRAWING)
3076 button_press_event = (gi->event.type == GD_EVENT_PRESSED);
3077 button_release_event = (gi->event.type == GD_EVENT_RELEASED);
3079 /* make sure to stay inside drawing area boundaries */
3080 sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
3081 sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
3085 /* get positions inside level field */
3086 lx = sx + level_xpos;
3087 ly = sy + level_ypos;
3089 /* make sure to stay inside level field boundaries */
3090 lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
3091 ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
3093 /* correct drawing area positions accordingly */
3094 sx = lx - level_xpos;
3095 sy = ly - level_ypos;
3098 if (button_press_event)
3099 started_inside_drawing_area = inside_drawing_area;
3101 if (!started_inside_drawing_area)
3104 if (!button && !button_release_event)
3107 new_element = (button == 1 ? new_element1 :
3108 button == 2 ? new_element2 :
3109 button == 3 ? new_element3 : 0);
3113 if (button_release_event)
3118 if (!draw_level && drawing_function != ED_CTRL_ID_SINGLE_ITEMS)
3121 switch (drawing_function)
3123 case ED_CTRL_ID_SINGLE_ITEMS:
3126 if (button_release_event)
3128 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3130 if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
3131 !inside_drawing_area)
3132 DeleteBrushFromCursor();
3138 if (draw_with_brush)
3139 CopyBrushToLevel(sx, sy, button);
3140 else if (new_element != Feld[lx][ly])
3142 if (new_element == EL_SPIELFIGUR)
3144 /* remove player at old position */
3145 for(y=0; y<lev_fieldy; y++)
3147 for(x=0; x<lev_fieldx; x++)
3149 if (Feld[x][y] == EL_SPIELFIGUR || Feld[x][y] == EL_SPIELER1)
3151 Feld[x][y] = EL_LEERRAUM;
3152 if (x - level_xpos >= 0 && x - level_xpos < ED_FIELDX &&
3153 y - level_ypos >= 0 && y - level_ypos < ED_FIELDY)
3154 DrawMiniElement(x - level_xpos, y - level_ypos,
3161 Feld[lx][ly] = new_element;
3162 DrawMiniElement(sx, sy, new_element);
3167 DrawMiniGraphicExt(drawto, gc,
3168 gi->x + sx * MINI_TILEX,
3169 gi->y + sy * MINI_TILEY,
3170 el2gfx(new_element));
3171 DrawMiniGraphicExt(window, gc,
3172 gi->x + sx * MINI_TILEX,
3173 gi->y + sy * MINI_TILEY,
3174 el2gfx(new_element));
3176 if (id == ED_CTRL_ID_AMOEBA_CONTENT)
3177 level.amoebe_inhalt = new_element;
3178 else if (id >= ED_CTRL_ID_ELEMCONT_0 && id <= ED_CTRL_ID_ELEMCONT_7)
3179 level.mampfer_inhalt[id - ED_CTRL_ID_ELEMCONT_0][sx][sy] =
3184 case ED_CTRL_ID_CONNECTED_ITEMS:
3186 static int last_sx = -1;
3187 static int last_sy = -1;
3189 if (button_release_event)
3190 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3194 if (!button_press_event)
3195 DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
3203 case ED_CTRL_ID_LINE:
3204 case ED_CTRL_ID_RECTANGLE:
3205 case ED_CTRL_ID_FILLED_BOX:
3206 case ED_CTRL_ID_GRAB_BRUSH:
3207 case ED_CTRL_ID_TEXT:
3209 static int last_sx = -1;
3210 static int last_sy = -1;
3211 static int start_sx = -1;
3212 static int start_sy = -1;
3213 void (*draw_func)(int, int, int, int, int, boolean);
3215 if (drawing_function == ED_CTRL_ID_LINE)
3216 draw_func = DrawLine;
3217 else if (drawing_function == ED_CTRL_ID_RECTANGLE)
3218 draw_func = DrawRectangle;
3219 else if (drawing_function == ED_CTRL_ID_FILLED_BOX)
3220 draw_func = DrawFilledBox;
3221 else if (drawing_function == ED_CTRL_ID_GRAB_BRUSH)
3222 draw_func = SelectArea;
3223 else /* (drawing_function == ED_CTRL_ID_TEXT) */
3224 draw_func = SetTextCursor;
3226 if (button_press_event)
3228 draw_func(sx, sy, sx, sy, new_element, FALSE);
3229 start_sx = last_sx = sx;
3230 start_sy = last_sy = sy;
3232 if (drawing_function == ED_CTRL_ID_TEXT)
3233 DrawLevelText(0, 0, 0, TEXT_END);
3235 else if (button_release_event)
3237 draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
3238 if (drawing_function == ED_CTRL_ID_GRAB_BRUSH)
3240 CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
3241 CopyBrushToCursor(sx, sy);
3242 ClickOnGadget(level_editor_gadget[ED_CTRL_ID_SINGLE_ITEMS]);
3243 draw_with_brush = TRUE;
3245 else if (drawing_function == ED_CTRL_ID_TEXT)
3246 DrawLevelText(sx, sy, 0, TEXT_INIT);
3248 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3250 else if (last_sx != sx || last_sy != sy)
3252 draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
3253 draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
3263 case ED_CTRL_ID_TEXT:
3265 DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
3266 DrawAreaBorder(sx, sy, sx, sy);
3271 if (button_press_event)
3272 DrawLevelText(sx, sy, 0, TEXT_INIT);
3278 case ED_CTRL_ID_FLOOD_FILL:
3279 if (button_press_event && Feld[lx][ly] != new_element)
3281 FloodFill(lx, ly, new_element);
3282 DrawMiniLevel(level_xpos, level_ypos);
3283 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
3287 case ED_CTRL_ID_PICK_ELEMENT:
3288 if (button_press_event)
3289 PickDrawingElement(button, Feld[lx][ly]);
3290 if (button_release_event)
3291 ClickOnGadget(level_editor_gadget[last_drawing_function]);
3299 static void HandleCounterButtons(struct GadgetInfo *gi)
3301 int id = gi->custom_id;
3302 int button = gi->event.button;
3303 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3307 case ED_CTRL_ID_SCORE_DOWN:
3308 case ED_CTRL_ID_SCORE_UP:
3309 step *= (id == ED_CTRL_ID_SCORE_DOWN ? -1 : 1);
3310 ModifyEditorCounter(ED_COUNTER_ID_SCORE, *gadget_score_value + step);
3312 case ED_CTRL_ID_SCORE_TEXT:
3313 *gadget_score_value = gi->text.number_value;
3316 case ED_CTRL_ID_ELEMCONT_DOWN:
3317 case ED_CTRL_ID_ELEMCONT_UP:
3318 step *= (id == ED_CTRL_ID_ELEMCONT_DOWN ? -1 : 1);
3319 ModifyEditorCounter(ED_COUNTER_ID_ELEMCONT, *gadget_areas_value + step);
3320 DrawElementContentAreas();
3322 case ED_CTRL_ID_ELEMCONT_TEXT:
3323 *gadget_areas_value = gi->text.number_value;
3324 DrawElementContentAreas();
3332 static void HandleTextInputGadgets(struct GadgetInfo *gi)
3334 int id = gi->custom_id;
3338 case ED_CTRL_ID_LEVEL_NAME:
3339 strcpy(level.name, gi->text.value);
3347 static void HandleControlButtons(struct GadgetInfo *gi)
3349 int id = gi->custom_id;
3350 int button = gi->event.button;
3351 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3353 int player_present = FALSE;
3354 int level_changed = FALSE;
3357 new_element = (button == 1 ? new_element1 :
3358 button == 2 ? new_element2 :
3359 button == 3 ? new_element3 : 0);
3361 if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT)
3362 DrawLevelText(0, 0, 0, TEXT_END);
3364 if (id < ED_NUM_CTRL1_BUTTONS && id != ED_CTRL_ID_PROPERTIES &&
3365 edit_mode != ED_MODE_DRAWING)
3367 DrawDrawingWindow();
3368 edit_mode = ED_MODE_DRAWING;
3373 case ED_CTRL_ID_SCROLL_LEFT:
3374 if (level_xpos >= 0)
3376 int gadget_id = ED_CTRL_ID_SCROLL_HORIZONTAL;
3377 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3378 struct GadgetScrollbar *gs = &gi->scrollbar;
3380 if (lev_fieldx < ED_FIELDX - 2)
3384 if (level_xpos < -1)
3387 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
3389 DrawMiniLevel(level_xpos, level_ypos);
3391 AdjustScrollbar(gi, gs->items_max, level_xpos + 1);
3395 case ED_CTRL_ID_SCROLL_RIGHT:
3396 if (level_xpos <= lev_fieldx - ED_FIELDX)
3398 int gadget_id = ED_CTRL_ID_SCROLL_HORIZONTAL;
3399 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3400 struct GadgetScrollbar *gs = &gi->scrollbar;
3402 if (lev_fieldx < ED_FIELDX - 2)
3406 if (level_xpos > lev_fieldx - ED_FIELDX + 1)
3407 level_xpos = lev_fieldx - ED_FIELDX + 1;
3409 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
3411 DrawMiniLevel(level_xpos, level_ypos);
3413 AdjustScrollbar(gi, gs->items_max, level_xpos + 1);
3417 case ED_CTRL_ID_SCROLL_UP:
3418 if (level_ypos >= 0)
3420 int gadget_id = ED_CTRL_ID_SCROLL_VERTICAL;
3421 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3422 struct GadgetScrollbar *gs = &gi->scrollbar;
3424 if (lev_fieldy < ED_FIELDY - 2)
3428 if (level_ypos < -1)
3431 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
3433 DrawMiniLevel(level_xpos, level_ypos);
3435 AdjustScrollbar(gi, gs->items_max, level_ypos + 1);
3439 case ED_CTRL_ID_SCROLL_DOWN:
3440 if (level_ypos <= lev_fieldy - ED_FIELDY)
3442 int gadget_id = ED_CTRL_ID_SCROLL_VERTICAL;
3443 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3444 struct GadgetScrollbar *gs = &gi->scrollbar;
3446 if (lev_fieldy < ED_FIELDY - 2)
3450 if (level_ypos > lev_fieldy - ED_FIELDY + 1)
3451 level_ypos = lev_fieldy - ED_FIELDY + 1;
3453 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
3455 DrawMiniLevel(level_xpos, level_ypos);
3457 AdjustScrollbar(gi, gs->items_max, level_ypos + 1);
3461 case ED_CTRL_ID_SCROLL_HORIZONTAL:
3462 level_xpos = gi->event.item_position - 1;
3463 DrawMiniLevel(level_xpos, level_ypos);
3466 case ED_CTRL_ID_SCROLL_VERTICAL:
3467 level_ypos = gi->event.item_position - 1;
3468 DrawMiniLevel(level_xpos, level_ypos);
3471 case ED_CTRL_ID_WRAP_LEFT:
3472 WrapLevel(-step, 0);
3475 case ED_CTRL_ID_WRAP_RIGHT:
3479 case ED_CTRL_ID_WRAP_UP:
3480 WrapLevel(0, -step);
3483 case ED_CTRL_ID_WRAP_DOWN:
3487 case ED_CTRL_ID_SINGLE_ITEMS:
3488 case ED_CTRL_ID_CONNECTED_ITEMS:
3489 case ED_CTRL_ID_LINE:
3490 case ED_CTRL_ID_TEXT:
3491 case ED_CTRL_ID_RECTANGLE:
3492 case ED_CTRL_ID_FILLED_BOX:
3493 case ED_CTRL_ID_FLOOD_FILL:
3494 case ED_CTRL_ID_GRAB_BRUSH:
3495 case ED_CTRL_ID_PICK_ELEMENT:
3496 last_drawing_function = drawing_function;
3497 drawing_function = id;
3498 draw_with_brush = FALSE;
3501 case ED_CTRL_ID_RANDOM_PLACEMENT:
3502 RandomPlacement(button);
3505 case ED_CTRL_ID_PROPERTIES:
3506 if (edit_mode != ED_MODE_PROPERTIES)
3508 properties_element = new_element;
3509 DrawPropertiesWindow();
3510 edit_mode = ED_MODE_PROPERTIES;
3514 DrawDrawingWindow();
3515 edit_mode = ED_MODE_DRAWING;
3519 case ED_CTRL_ID_UNDO:
3520 if (undo_buffer_steps == 0)
3522 Request("Undo buffer empty !", REQ_CONFIRM);
3526 undo_buffer_position =
3527 (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
3528 undo_buffer_steps--;
3530 for(x=0; x<lev_fieldx; x++)
3531 for(y=0; y<lev_fieldy; y++)
3532 Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
3533 DrawMiniLevel(level_xpos,level_ypos);
3536 case ED_CTRL_ID_INFO:
3537 if (edit_mode != ED_MODE_INFO)
3539 DrawControlWindow();
3540 edit_mode = ED_MODE_INFO;
3544 DrawDrawingWindow();
3545 edit_mode = ED_MODE_DRAWING;
3549 case ED_CTRL_ID_CLEAR:
3550 for(x=0; x<MAX_LEV_FIELDX; x++)
3551 for(y=0; y<MAX_LEV_FIELDY; y++)
3552 Feld[x][y] = new_element3;
3553 CopyLevelToUndoBuffer(ED_CTRL_ID_CLEAR);
3555 DrawMiniLevel(level_xpos, level_ypos);
3558 case ED_CTRL_ID_SAVE:
3559 if (leveldir[leveldir_nr].readonly)
3561 Request("This level is read only !", REQ_CONFIRM);
3565 for(y=0; y<lev_fieldy; y++)
3566 for(x=0; x<lev_fieldx; x++)
3567 if (Feld[x][y] != Ur[x][y])
3568 level_changed = TRUE;
3570 if (0 && !level_changed)
3572 Request("Level has not changed !", REQ_CONFIRM);
3576 for(y=0; y<lev_fieldy; y++)
3577 for(x=0; x<lev_fieldx; x++)
3578 if (Feld[x][y] == EL_SPIELFIGUR ||
3579 Feld[x][y] == EL_SPIELER1 ||
3580 Feld[x][y] == EL_SP_MURPHY)
3581 player_present = TRUE;
3583 if (!player_present)
3584 Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3587 if (Request("Save this level and kill the old ?", REQ_ASK))
3589 for(x=0; x<lev_fieldx; x++)
3590 for(y=0; y<lev_fieldy; y++)
3591 Ur[x][y] = Feld[x][y];
3592 SaveLevel(level_nr);
3597 case ED_CTRL_ID_TEST:
3598 for(y=0; y<lev_fieldy; y++)
3599 for(x=0; x<lev_fieldx; x++)
3600 if (Feld[x][y] == EL_SPIELFIGUR ||
3601 Feld[x][y] == EL_SPIELER1 ||
3602 Feld[x][y] == EL_SP_MURPHY)
3603 player_present = TRUE;
3605 if (!player_present)
3606 Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3609 for(x=0; x<lev_fieldx; x++)
3610 for(y=0; y<lev_fieldy; y++)
3611 FieldBackup[x][y] = Ur[x][y];
3613 for(x=0; x<lev_fieldx; x++)
3614 for(y=0; y<lev_fieldy; y++)
3615 Ur[x][y] = Feld[x][y];
3617 UnmapLevelEditorGadgets();
3619 /* draw smaller door */
3620 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3621 DOOR_GFX_PAGEX7, 64,
3624 redraw_mask |= REDRAW_ALL;
3626 CloseDoor(DOOR_CLOSE_ALL);
3628 DrawCompleteVideoDisplay();
3630 if (setup.autorecord)
3631 TapeStartRecording();
3633 level_editor_test_game = TRUE;
3634 game_status = PLAYING;
3640 case ED_CTRL_ID_EXIT:
3641 for(y=0; y<lev_fieldy; y++)
3642 for(x=0; x<lev_fieldx; x++)
3643 if (Feld[x][y] != Ur[x][y])
3644 level_changed = TRUE;
3646 if (!level_changed ||
3647 Request("Level has changed! Exit without saving ?",
3648 REQ_ASK | REQ_STAY_OPEN))
3650 CloseDoor(DOOR_CLOSE_1);
3653 CloseDoor(DOOR_CLOSE_ALL);
3656 /* draw smaller door */
3657 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3658 DOOR_GFX_PAGEX7, 64,
3661 redraw_mask |= REDRAW_ALL;
3663 game_status = MAINMENU;
3668 CloseDoor(DOOR_CLOSE_1);
3669 XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
3670 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
3671 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3672 OpenDoor(DOOR_OPEN_1);
3678 if (gi->event.type == GD_EVENT_PRESSED)
3679 printf("default: HandleControlButtons: GD_EVENT_PRESSED\n");
3680 else if (gi->event.type == GD_EVENT_RELEASED)
3681 printf("default: HandleControlButtons: GD_EVENT_RELEASED\n");
3682 else if (gi->event.type == GD_EVENT_MOVING)
3683 printf("default: HandleControlButtons: GD_EVENT_MOVING\n");
3685 printf("default: HandleControlButtons: ?\n");
3691 void HandleLevelEditorKeyInput(KeySym key)
3693 if (edit_mode == ED_MODE_DRAWING)
3695 char letter = getCharFromKeySym(key);
3697 if (drawing_function == ED_CTRL_ID_TEXT)
3700 DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
3701 else if (key == XK_Delete || key == XK_BackSpace)
3702 DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
3703 else if (key == XK_Return)
3704 DrawLevelText(0, 0, 0, TEXT_NEWLINE);
3706 else if (button_status == MB_RELEASED)
3713 id = ED_CTRL_ID_SCROLL_LEFT;
3716 id = ED_CTRL_ID_SCROLL_RIGHT;
3719 id = ED_CTRL_ID_SCROLL_UP;
3722 id = ED_CTRL_ID_SCROLL_DOWN;
3726 id = ED_CTRL_ID_NONE;
3730 if (id != ED_CTRL_ID_NONE)
3731 ClickOnGadget(level_editor_gadget[id]);
3732 else if (letter == '.')
3733 ClickOnGadget(level_editor_gadget[ED_CTRL_ID_SINGLE_ITEMS]);
3735 for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
3736 if (letter && letter == control_info[i].shortcut)
3737 ClickOnGadget(level_editor_gadget[i]);
3742 /* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
3743 #define INFOTEXT_XPOS SX
3744 #define INFOTEXT_YPOS (SY + SYSIZE - MINI_TILEX + 2)
3745 #define INFOTEXT_XSIZE SXSIZE
3746 #define INFOTEXT_YSIZE MINI_TILEX
3747 #define MAX_INFOTEXT_LEN (SXSIZE / FONT2_XSIZE)
3749 void ClearEditorGadgetInfoText()
3751 XFillRectangle(display, drawto, gc,
3752 INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
3753 redraw_mask |= REDRAW_FIELD;
3756 void HandleEditorGadgetInfoText(void *ptr)
3758 struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
3759 char infotext[MAX_INFOTEXT_LEN + 1];
3762 ClearEditorGadgetInfoText();
3764 /* misuse this function to delete brush cursor, if needed */
3765 if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
3766 DeleteBrushFromCursor();
3768 if (gi == NULL || gi->description_text == NULL)
3771 strncpy(infotext, gi->description_text, MAX_INFOTEXT_LEN);
3772 infotext[MAX_INFOTEXT_LEN] = '\0';
3774 if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
3776 int key = control_info[gi->custom_id].shortcut;
3780 sprintf(shortcut, " ('%s%c')",
3781 (key >= 'A' && key <= 'Z' ? "Shift-" :
3782 gi->custom_id == ED_CTRL_ID_SINGLE_ITEMS ? ".' or '" : ""),
3785 if (strlen(infotext) + strlen(shortcut) <= MAX_INFOTEXT_LEN)
3786 strcat(infotext, shortcut);
3790 DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FS_SMALL, FC_YELLOW);
3793 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
3795 static int start_lx, start_ly;
3797 int id = gi->custom_id;
3798 int sx = gi->event.x;
3799 int sy = gi->event.y;
3800 int lx = sx + level_xpos;
3801 int ly = sy + level_ypos;
3803 ClearEditorGadgetInfoText();
3805 if (id == ED_CTRL_ID_DRAWING_LEVEL)
3809 int min_sx = 0, min_sy = 0;
3810 int max_sx = gi->drawing.area_xsize - 1;
3811 int max_sy = gi->drawing.area_ysize - 1;
3812 int min_lx = 0, min_ly = 0;
3813 int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
3815 /* make sure to stay inside drawing area boundaries */
3816 sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
3817 sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
3819 /* get positions inside level field */
3820 lx = sx + level_xpos;
3821 ly = sy + level_ypos;
3823 /* make sure to stay inside level field boundaries */
3824 lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
3825 ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
3827 /* correct drawing area positions accordingly */
3828 sx = lx - level_xpos;
3829 sy = ly - level_ypos;
3832 if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
3834 if (button_status) /* if (gi->state == GD_BUTTON_PRESSED) */
3836 if (gi->event.type == GD_EVENT_PRESSED)
3842 switch (drawing_function)
3844 case ED_CTRL_ID_SINGLE_ITEMS:
3845 infotext = "Drawing single items";
3847 case ED_CTRL_ID_CONNECTED_ITEMS:
3848 infotext = "Drawing connected items";
3850 case ED_CTRL_ID_LINE:
3851 infotext = "Drawing line";
3853 case ED_CTRL_ID_TEXT:
3854 infotext = "Setting text cursor";
3856 case ED_CTRL_ID_RECTANGLE:
3857 infotext = "Drawing rectangle";
3859 case ED_CTRL_ID_FILLED_BOX:
3860 infotext = "Drawing filled box";
3862 case ED_CTRL_ID_FLOOD_FILL:
3863 infotext = "Flood fill";
3865 case ED_CTRL_ID_GRAB_BRUSH:
3866 infotext = "Grabbing brush";
3868 case ED_CTRL_ID_PICK_ELEMENT:
3869 infotext = "Picking element";
3873 infotext = "Drawing position";
3877 DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3878 "%s: %d, %d", infotext,
3879 ABS(lx - start_lx) + 1,
3880 ABS(ly - start_ly) + 1);
3883 DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3884 "Level position: %d, %d", lx, ly);
3887 /* misuse this function to draw brush cursor, if needed */
3888 if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
3890 if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
3891 CopyBrushToCursor(sx, sy);
3893 DeleteBrushFromCursor();
3896 else if (id == ED_CTRL_ID_AMOEBA_CONTENT)
3897 DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3900 DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3901 "Cruncher %d content: %d, %d", id - ED_CTRL_ID_ELEMCONT_0 + 1,