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 content */
53 #define MAX_ELEMCONT 8
55 /* values for the control window */
56 #define ED_CTRL_BUTTONS_GFX_YPOS 236
57 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS 142
59 #define ED_CTRL1_BUTTONS_HORIZ 4
60 #define ED_CTRL1_BUTTONS_VERT 4
61 #define ED_CTRL1_BUTTON_XSIZE 22
62 #define ED_CTRL1_BUTTON_YSIZE 22
63 #define ED_CTRL1_BUTTONS_XPOS 6
64 #define ED_CTRL1_BUTTONS_YPOS 6
65 #define ED_CTRL2_BUTTONS_HORIZ 3
66 #define ED_CTRL2_BUTTONS_VERT 2
67 #define ED_CTRL2_BUTTON_XSIZE 30
68 #define ED_CTRL2_BUTTON_YSIZE 20
69 #define ED_CTRL2_BUTTONS_XPOS 5
70 #define ED_CTRL2_BUTTONS_YPOS 100
71 #define ED_NUM_CTRL1_BUTTONS (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
72 #define ED_NUM_CTRL2_BUTTONS (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
73 #define ED_NUM_CTRL_BUTTONS (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
75 /* values for properties window */
76 #define ED_PROPERTIES_XPOS (TILEX - MINI_TILEX/2)
77 /* values for counter gadgets */
78 #define ED_COUNT_VALUE_XOFFSET 5
79 #define ED_COUNT_VALUE_YOFFSET 3
80 #define ED_COUNT_SCORE_XPOS ED_PROPERTIES_XPOS
81 #define ED_COUNT_SCORE_YPOS (14 * MINI_TILEY)
82 #define ED_COUNT_ELEMCONT_XPOS ED_PROPERTIES_XPOS
83 #define ED_COUNT_ELEMCONT_YPOS (17 * MINI_TILEY)
85 /* values for element content drawing areas */
86 #define ED_AREA_ELEMCONT_XPOS (TILEX)
87 #define ED_AREA_ELEMCONT_YPOS (10 * TILEY)
89 /* values for scrolling gadgets */
91 #define ED_SCROLLBUTTON_XSIZE 16
92 #define ED_SCROLLBUTTON_YSIZE 16
94 #define ED_SCROLLBUTTON_XPOS 24
95 #define ED_SCROLLBUTTON_YPOS 0
96 #define ED_SCROLLBAR_XPOS 24
97 #define ED_SCROLLBAR_YPOS 64
99 #define ED_SCROLLBUTTON_XSIZE 30
100 #define ED_SCROLLBUTTON_YSIZE 30
102 #define ED_SCROLLBUTTON_XPOS 70
103 #define ED_SCROLLBUTTON_YPOS 0
104 #define ED_SCROLLBAR_XPOS 10
105 #define ED_SCROLLBAR_YPOS 110
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 - TILEX - ED_SCROLLBUTTON_YSIZE)
112 #define ED_SCROLL_LEFT_XPOS (0)
113 #define ED_SCROLL_LEFT_YPOS (SYSIZE - ED_SCROLLBUTTON_YSIZE)
114 #define ED_SCROLL_RIGHT_XPOS (SXSIZE - TILEX - 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 - TILEY - 2 * ED_SCROLLBUTTON_YSIZE)
120 #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + ED_SCROLLBUTTON_XSIZE)
121 #define ED_SCROLL_HORIZONTAL_YPOS (SYSIZE - ED_SCROLLBUTTON_YSIZE)
122 #define ED_SCROLL_HORIZONTAL_XSIZE (SXSIZE - TILEX - 2 * ED_SCROLLBUTTON_XSIZE)
123 #define ED_SCROLL_HORIZONTAL_YSIZE ED_SCROLLBUTTON_YSIZE
125 /* control button identifiers */
126 #define ED_CTRL_ID_SINGLE_ITEMS 0
127 #define ED_CTRL_ID_CONNECTED_ITEMS 1
128 #define ED_CTRL_ID_LINE 2
129 #define ED_CTRL_ID_TEXT 3
130 #define ED_CTRL_ID_RECTANGLE 4
131 #define ED_CTRL_ID_FILLED_BOX 5
132 #define ED_CTRL_ID_WRAP_UP 6
133 #define ED_CTRL_ID_PROPERTIES 7
134 #define ED_CTRL_ID_FLOOD_FILL 8
135 #define ED_CTRL_ID_WRAP_LEFT 9
136 #define ED_CTRL_ID_UNUSED1 10
137 #define ED_CTRL_ID_WRAP_RIGHT 11
138 #define ED_CTRL_ID_RANDOM_PLACEMENT 12
139 #define ED_CTRL_ID_BRUSH 13
140 #define ED_CTRL_ID_WRAP_DOWN 14
141 #define ED_CTRL_ID_PICK_ELEMENT 15
142 #define ED_CTRL_ID_UNDO 16
143 #define ED_CTRL_ID_INFO 17
144 #define ED_CTRL_ID_SAVE 18
145 #define ED_CTRL_ID_CLEAR 19
146 #define ED_CTRL_ID_TEST 20
147 #define ED_CTRL_ID_EXIT 21
149 /* counter button identifiers */
150 #define ED_CTRL_ID_SCORE_DOWN 22
151 #define ED_CTRL_ID_SCORE_UP 23
152 #define ED_CTRL_ID_ELEMCONT_DOWN 24
153 #define ED_CTRL_ID_ELEMCONT_UP 25
155 /* drawing area identifiers */
156 #define ED_CTRL_ID_DRAWING_LEVEL 26
157 #define ED_CTRL_ID_ELEMCONT_0 27
158 #define ED_CTRL_ID_ELEMCONT_7 34
159 #define ED_CTRL_ID_AMOEBA_CONTENT 35
161 /* text input identifiers */
162 #define ED_CTRL_ID_LEVEL_NAME 36
164 /* gadgets for scrolling of drawing area */
165 #define ED_CTRL_ID_SCROLL_UP 37
166 #define ED_CTRL_ID_SCROLL_DOWN 38
167 #define ED_CTRL_ID_SCROLL_LEFT 39
168 #define ED_CTRL_ID_SCROLL_RIGHT 40
169 #define ED_CTRL_ID_SCROLL_VERTICAL 41
170 #define ED_CTRL_ID_SCROLL_HORIZONTAL 42
172 #define ED_NUM_GADGETS 43
174 /* values for counter gadgets */
175 #define ED_COUNTER_SCORE 0
176 #define ED_COUNTER_ELEMCONT 1
178 #define ED_NUM_COUNTERBUTTONS 2
179 #define ED_NUM_SCROLLBUTTONS 4
180 #define ED_NUM_SCROLLBARS 2
182 /* values for CopyLevelToUndoBuffer() */
183 #define UNDO_IMMEDIATE 0
184 #define UNDO_ACCUMULATE 1
190 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
192 { ED_COUNT_SCORE_XPOS, ED_COUNT_SCORE_YPOS, ED_CTRL_ID_SCORE_DOWN },
193 { ED_COUNT_ELEMCONT_XPOS, ED_COUNT_ELEMCONT_YPOS, ED_CTRL_ID_ELEMCONT_DOWN }
201 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
203 { ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 0 * ED_SCROLLBUTTON_YSIZE,
204 ED_SCROLL_UP_XPOS, ED_SCROLL_UP_YPOS, ED_CTRL_ID_SCROLL_UP },
205 { ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 1 * ED_SCROLLBUTTON_YSIZE,
206 ED_SCROLL_DOWN_XPOS, ED_SCROLL_DOWN_YPOS, ED_CTRL_ID_SCROLL_DOWN },
207 { ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
208 ED_SCROLL_LEFT_XPOS, ED_SCROLL_LEFT_YPOS, ED_CTRL_ID_SCROLL_LEFT },
209 { ED_SCROLLBUTTON_XPOS, ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
210 ED_SCROLL_RIGHT_XPOS, ED_SCROLL_RIGHT_YPOS, ED_CTRL_ID_SCROLL_RIGHT }
220 } scrollbar_info[ED_NUM_SCROLLBARS] =
222 { ED_SCROLLBAR_XPOS, ED_SCROLLBAR_YPOS,
223 ED_SCROLL_VERTICAL_XPOS, ED_SCROLL_VERTICAL_YPOS,
224 ED_SCROLL_VERTICAL_XSIZE, ED_SCROLL_VERTICAL_YSIZE,
225 GD_TYPE_SCROLLBAR_VERTICAL,
226 ED_CTRL_ID_SCROLL_VERTICAL },
227 { ED_SCROLLBAR_XPOS, ED_SCROLLBAR_YPOS,
228 ED_SCROLL_HORIZONTAL_XPOS, ED_SCROLL_HORIZONTAL_YPOS,
229 ED_SCROLL_HORIZONTAL_XSIZE, ED_SCROLL_HORIZONTAL_YSIZE,
230 GD_TYPE_SCROLLBAR_HORIZONTAL,
231 ED_CTRL_ID_SCROLL_HORIZONTAL },
235 /* forward declaration for internal use */
236 static void DrawDrawingWindow();
237 static void DrawPropertiesWindow();
238 static void CopyLevelToUndoBuffer(int);
239 static void HandleControlButtons(struct GadgetInfo *);
240 static void HandleCounterButtons(struct GadgetInfo *);
241 static void HandleDrawingAreas(struct GadgetInfo *);
242 static void HandleTextInputGadgets(struct GadgetInfo *);
244 static struct GadgetInfo *level_editor_gadget[ED_NUM_GADGETS];
245 static boolean level_editor_gadgets_created = FALSE;
247 static int drawing_function = ED_CTRL_ID_SINGLE_ITEMS;
248 static int last_drawing_function = ED_CTRL_ID_SINGLE_ITEMS;
249 static int properties_element = 0;
251 static short ElementContent[MAX_ELEMCONT][3][3];
252 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
253 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
254 static int undo_buffer_position = 0;
255 static int undo_buffer_steps = 0;
257 static int random_placement_percentage = 10;
258 static int random_placement_num_objects = 10;
260 static int random_placement_method = RANDOM_USE_PERCENTAGE;
262 static int random_placement_method = RANDOM_USE_NUM_OBJECTS;
265 /* pointer to score value */
266 static int *gadget_score_value;
267 static int *gadget_areas_value;
269 static int level_xpos,level_ypos;
270 static int edit_mode;
271 static boolean name_typing;
272 static int new_element1 = EL_MAUERWERK;
273 static int new_element2 = EL_LEERRAUM;
274 static int new_element3 = EL_ERDREICH;
276 int element_shift = 0;
278 int editor_element[] =
280 EL_CHAR_A + ('B' - 'A'),
281 EL_CHAR_A + ('O' - 'A'),
282 EL_CHAR_A + ('U' - 'A'),
283 EL_CHAR_A + ('L' - 'A'),
286 EL_CHAR_A + ('D' - 'A'),
287 EL_CHAR_A + ('E' - 'A'),
288 EL_CHAR_A + ('R' - 'A'),
290 EL_CHAR_A + ('D' - 'A'),
291 EL_CHAR_A + ('A' - 'A'),
292 EL_CHAR_A + ('S' - 'A'),
293 EL_CHAR_A + ('H' - 'A'),
320 EL_CHAR_A + ('E' - 'A'),
321 EL_CHAR_A + ('M' - 'A'),
322 EL_CHAR_A + ('E' - 'A'),
325 EL_CHAR_A + ('R' - 'A'),
326 EL_CHAR_A + ('A' - 'A'),
327 EL_CHAR_A + ('L' - 'A'),
328 EL_CHAR_A + ('D' - 'A'),
330 EL_CHAR_A + ('M' - 'A'),
331 EL_CHAR_A + ('I' - 'A'),
332 EL_CHAR_A + ('N' - 'A'),
333 EL_CHAR_A + ('E' - 'A'),
410 EL_CHAR_A + ('M' - 'A'),
411 EL_CHAR_A + ('O' - 'A'),
412 EL_CHAR_A + ('R' - 'A'),
413 EL_CHAR_A + ('E' - 'A'),
465 EL_CHAR_A + ('S' - 'A'),
466 EL_CHAR_A + ('O' - 'A'),
467 EL_CHAR_A + ('K' - 'A'),
468 EL_CHAR_A + ('O' - 'A'),
471 EL_CHAR_A + ('B' - 'A'),
472 EL_CHAR_A + ('A' - 'A'),
473 EL_CHAR_A + ('N' - 'A'),
476 EL_SOKOBAN_FELD_LEER,
477 EL_SOKOBAN_FELD_VOLL,
546 EL_CHAR_A + ('D' - 'A'),
547 EL_CHAR_A + ('Y' - 'A'),
548 EL_CHAR_A + ('N' - 'A'),
549 EL_CHAR_A + ('A' - 'A'),
551 EL_CHAR_A + ('B' - 'A'),
552 EL_CHAR_A + ('L' - 'A'),
553 EL_CHAR_A + ('A' - 'A'),
554 EL_CHAR_A + ('S' - 'A'),
557 EL_CHAR_A + ('T' - 'A'),
558 EL_CHAR_A + ('E' - 'A'),
559 EL_CHAR_A + ('R' - 'A'),
642 int elements_in_list = sizeof(editor_element)/sizeof(int);
644 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
647 int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
648 int dy = (scroll == ED_SCROLL_UP ? -1 : scroll == ED_SCROLL_DOWN ? 1 : 0);
650 XCopyArea(display, drawto, drawto, gc,
651 SX + (dx == -1 ? MINI_TILEX : 0),
652 SY + (dy == -1 ? MINI_TILEY : 0),
653 (ED_FIELDX * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
654 (ED_FIELDY * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
655 SX + (dx == +1 ? MINI_TILEX : 0),
656 SY + (dy == +1 ? MINI_TILEY : 0));
659 x = (dx == 1 ? 0 : ED_FIELDX - 1);
660 for(y=0; y<ED_FIELDY; y++)
661 DrawMiniElementOrWall(x, y, from_x, from_y);
665 y = (dy == 1 ? 0 : ED_FIELDY - 1);
666 for(x=0; x<ED_FIELDX; x++)
667 DrawMiniElementOrWall(x, y, from_x, from_y);
670 redraw_mask |= REDRAW_FIELD;
674 void InitLevelEditorGadgets()
678 for (i=0; i<ED_NUM_GADGETS; i++)
679 level_editor_gadget[i] = NULL;
682 static void CreateControlButtons()
684 Pixmap gd_pixmap = pix[PIX_DOOR];
685 struct GadgetInfo *gi;
686 unsigned long event_mask;
689 /* create toolbox buttons */
690 for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
694 int gd_xoffset, gd_yoffset;
695 int gd_x1, gd_x2, gd_y1, gd_y2;
698 boolean radio_button_pressed;
700 if (id == ED_CTRL_ID_SINGLE_ITEMS ||
701 id == ED_CTRL_ID_CONNECTED_ITEMS ||
702 id == ED_CTRL_ID_LINE ||
703 id == ED_CTRL_ID_TEXT ||
704 id == ED_CTRL_ID_RECTANGLE ||
705 id == ED_CTRL_ID_FILLED_BOX ||
706 id == ED_CTRL_ID_FLOOD_FILL ||
707 id == ED_CTRL_ID_BRUSH ||
708 id == ED_CTRL_ID_PICK_ELEMENT)
710 button_type = GD_TYPE_RADIO_BUTTON;
712 radio_button_pressed = (id == drawing_function ? TRUE : FALSE);
713 event_mask = GD_EVENT_PRESSED;
717 button_type = GD_TYPE_NORMAL_BUTTON;
719 radio_button_pressed = FALSE;
721 if (id == ED_CTRL_ID_WRAP_LEFT ||
722 id == ED_CTRL_ID_WRAP_RIGHT ||
723 id == ED_CTRL_ID_WRAP_UP ||
724 id == ED_CTRL_ID_WRAP_DOWN)
725 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
727 event_mask = GD_EVENT_RELEASED;
730 if (id < ED_NUM_CTRL1_BUTTONS)
732 int x = i % ED_CTRL1_BUTTONS_HORIZ;
733 int y = i / ED_CTRL1_BUTTONS_HORIZ;
735 gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
736 gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
737 width = ED_CTRL1_BUTTON_XSIZE;
738 height = ED_CTRL1_BUTTON_YSIZE;
742 int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
743 int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
745 gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
746 gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
747 width = ED_CTRL2_BUTTON_XSIZE;
748 height = ED_CTRL2_BUTTON_YSIZE;
751 gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
752 gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
753 gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_GFX_YPOS + gd_yoffset;
754 gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
756 gi = CreateGadget(GDI_CUSTOM_ID, id,
757 GDI_X, EX + gd_xoffset,
758 GDI_Y, EY + gd_yoffset,
761 GDI_TYPE, button_type,
762 GDI_STATE, GD_BUTTON_UNPRESSED,
763 GDI_RADIO_NR, radio_button_nr,
764 GDI_RADIO_PRESSED, radio_button_pressed,
765 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
766 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
767 GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
768 GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
769 GDI_EVENT_MASK, event_mask,
770 GDI_CALLBACK, HandleControlButtons,
774 Error(ERR_EXIT, "cannot create gadget");
776 level_editor_gadget[id] = gi;
779 /* create buttons for scrolling of drawing area */
780 for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
782 int id = scrollbutton_info[i].gadget_id;
783 int gd_x1, gd_x2, gd_y;
785 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
787 gd_y = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
788 gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].xpos;
789 gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
791 gi = CreateGadget(GDI_CUSTOM_ID, id,
792 GDI_X, SX + scrollbutton_info[i].x,
793 GDI_Y, SY + scrollbutton_info[i].y,
794 GDI_WIDTH, ED_SCROLLBUTTON_XSIZE,
795 GDI_HEIGHT, ED_SCROLLBUTTON_YSIZE,
796 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
797 GDI_STATE, GD_BUTTON_UNPRESSED,
798 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
799 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
800 GDI_EVENT_MASK, event_mask,
801 GDI_CALLBACK, HandleControlButtons,
805 Error(ERR_EXIT, "cannot create gadget");
807 level_editor_gadget[id] = gi;
811 static void CreateCounterButtons()
815 for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
819 Pixmap gd_pixmap = pix[PIX_DOOR];
820 struct GadgetInfo *gi;
821 int id = counterbutton_info[i].gadget_id + j;
823 int gd_x1, gd_x2, gd_y;
824 unsigned long event_mask;
826 event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
828 gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
829 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
830 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
831 gd_y = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
833 gi = CreateGadget(GDI_CUSTOM_ID, id,
834 GDI_X, SX + counterbutton_info[i].x + gd_xoffset,
835 GDI_Y, SY + counterbutton_info[i].y,
836 GDI_WIDTH, ED_BUTTON_COUNT_XSIZE,
837 GDI_HEIGHT, ED_BUTTON_COUNT_YSIZE,
838 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
839 GDI_STATE, GD_BUTTON_UNPRESSED,
840 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
841 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
842 GDI_EVENT_MASK, event_mask,
843 GDI_CALLBACK, HandleCounterButtons,
847 Error(ERR_EXIT, "cannot create gadget");
849 level_editor_gadget[id] = gi;
854 static void CreateDrawingAreas()
856 struct GadgetInfo *gi;
857 unsigned long event_mask;
862 GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
863 GD_EVENT_OFF_BORDERS;
865 /* one for the level drawing area ... */
866 id = ED_CTRL_ID_DRAWING_LEVEL;
867 gi = CreateGadget(GDI_CUSTOM_ID, id,
876 GDI_TYPE, GD_TYPE_DRAWING_AREA,
877 GDI_AREA_SIZE, ED_FIELDX, ED_FIELDY,
878 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
879 GDI_EVENT_MASK, event_mask,
880 GDI_CALLBACK, HandleDrawingAreas,
884 Error(ERR_EXIT, "cannot create gadget");
886 level_editor_gadget[id] = gi;
888 /* ... up to eight areas for element content ... */
889 for (i=0; i<MAX_ELEMCONT; i++)
891 int gx = SX + ED_AREA_ELEMCONT_XPOS + 5 * (i % 4) * MINI_TILEX;
892 int gy = SX + ED_AREA_ELEMCONT_YPOS + 6 * (i / 4) * MINI_TILEY;
894 id = ED_CTRL_ID_ELEMCONT_0 + i;
895 gi = CreateGadget(GDI_CUSTOM_ID, id,
898 GDI_WIDTH, 3 * MINI_TILEX,
899 GDI_HEIGHT, 3 * MINI_TILEY,
900 GDI_TYPE, GD_TYPE_DRAWING_AREA,
901 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
902 GDI_EVENT_MASK, event_mask,
903 GDI_CALLBACK, HandleDrawingAreas,
907 Error(ERR_EXIT, "cannot create gadget");
909 level_editor_gadget[id] = gi;
912 /* ... and one for the amoeba content */
913 id = ED_CTRL_ID_AMOEBA_CONTENT;
914 gi = CreateGadget(GDI_CUSTOM_ID, id,
915 GDI_X, SX + ED_AREA_ELEMCONT_XPOS,
916 GDI_Y, SY + ED_AREA_ELEMCONT_YPOS,
917 GDI_WIDTH, MINI_TILEX,
918 GDI_HEIGHT, MINI_TILEY,
919 GDI_TYPE, GD_TYPE_DRAWING_AREA,
920 GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
921 GDI_EVENT_MASK, event_mask,
922 GDI_CALLBACK, HandleDrawingAreas,
926 Error(ERR_EXIT, "cannot create gadget");
928 level_editor_gadget[id] = gi;
931 static void CreateTextInputGadgets()
933 Pixmap gd_pixmap = pix[PIX_DOOR];
935 struct GadgetInfo *gi;
936 unsigned long event_mask;
939 gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
940 gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
941 event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
943 /* text input gadget for the level name */
944 id = ED_CTRL_ID_LEVEL_NAME;
945 gi = CreateGadget(GDI_CUSTOM_ID, id,
946 GDI_X, SX + ED_COUNT_ELEMCONT_XPOS,
947 GDI_Y, SY + ED_AREA_ELEMCONT_YPOS + 3 * TILEX,
948 GDI_TYPE, GD_TYPE_TEXTINPUT,
949 GDI_TEXT_VALUE, level.name,
951 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x, gd_y,
952 GDI_DESIGN_PRESSED, gd_pixmap, gd_x, gd_y,
953 GDI_DESIGN_BORDER, 3,
954 GDI_EVENT_MASK, event_mask,
955 GDI_CALLBACK, HandleTextInputGadgets,
959 Error(ERR_EXIT, "cannot create gadget");
961 level_editor_gadget[id] = gi;
964 static void CreateScrollbarGadgets()
968 for (i=0; i<ED_NUM_SCROLLBARS; i++)
970 int id = scrollbar_info[i].gadget_id;
971 Pixmap gd_pixmap = pix[PIX_DOOR];
972 int gd_x1, gd_x2, gd_y1, gd_y2;
973 struct GadgetInfo *gi;
974 int items_max, items_visible, item_position;
975 unsigned long event_mask;
977 if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
979 items_max = lev_fieldx + 2;
980 items_visible = ED_FIELDX;
985 items_max = lev_fieldy + 2;
986 items_visible = ED_FIELDY;
990 event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
993 gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].xpos;
994 gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
995 gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
996 gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
998 gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].xpos;
999 gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1001 gd_y2 = gd_y1 - ED_SCROLLBUTTON_YSIZE;
1004 gi = CreateGadget(GDI_CUSTOM_ID, id,
1005 GDI_X, SX + scrollbar_info[i].x,
1006 GDI_Y, SY + scrollbar_info[i].y,
1007 GDI_WIDTH, scrollbar_info[i].width,
1008 GDI_HEIGHT, scrollbar_info[i].height,
1009 GDI_TYPE, scrollbar_info[i].type,
1010 GDI_SCROLLBAR_ITEMS_MAX, items_max,
1011 GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1012 GDI_SCROLLBAR_ITEM_POSITION, item_position,
1013 GDI_STATE, GD_BUTTON_UNPRESSED,
1014 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
1015 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
1016 GDI_DESIGN_BORDER, 3,
1017 GDI_EVENT_MASK, event_mask,
1018 GDI_CALLBACK, HandleControlButtons,
1022 Error(ERR_EXIT, "cannot create gadget");
1024 level_editor_gadget[id] = gi;
1028 static void CreateLevelEditorGadgets()
1030 if (level_editor_gadgets_created)
1033 CreateControlButtons();
1034 CreateCounterButtons();
1035 CreateDrawingAreas();
1036 CreateTextInputGadgets();
1037 CreateScrollbarGadgets();
1039 level_editor_gadgets_created = TRUE;
1042 static void MapControlButtons()
1046 for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
1047 MapGadget(level_editor_gadget[i]);
1050 static void MapCounterButtons(int id)
1055 MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id + i]);
1058 static void MapDrawingArea(int id)
1060 MapGadget(level_editor_gadget[id]);
1063 static void MapTextInputGadget(int id)
1065 MapGadget(level_editor_gadget[id]);
1068 static void MapMainDrawingArea()
1072 for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
1073 MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
1075 for (i=0; i<ED_NUM_SCROLLBARS; i++)
1076 MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
1078 MapDrawingArea(ED_CTRL_ID_DRAWING_LEVEL);
1081 static void UnmapDrawingArea(int id)
1083 UnmapGadget(level_editor_gadget[id]);
1086 void UnmapLevelEditorWindowGadgets()
1090 for (i=ED_NUM_CTRL_BUTTONS; i<ED_NUM_GADGETS; i++)
1091 UnmapGadget(level_editor_gadget[i]);
1094 void UnmapLevelEditorGadgets()
1098 for (i=0; i<ED_NUM_GADGETS; i++)
1099 UnmapGadget(level_editor_gadget[i]);
1104 int i, x, y, graphic;
1108 edit_mode = ED_MODE_DRAWING;
1109 name_typing = FALSE;
1111 CloseDoor(DOOR_CLOSE_ALL);
1113 OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
1115 if (level_editor_test_game)
1117 for(x=0; x<lev_fieldx; x++)
1118 for(y=0; y<lev_fieldy; y++)
1119 Feld[x][y] = Ur[x][y];
1121 for(x=0; x<lev_fieldx; x++)
1122 for(y=0; y<lev_fieldy; y++)
1123 Ur[x][y] = FieldBackup[x][y];
1125 level_editor_test_game = FALSE;
1129 undo_buffer_position = -1;
1130 undo_buffer_steps = -1;
1131 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
1135 DrawMiniLevel(level_xpos, level_ypos);
1139 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1140 DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY1,
1142 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1143 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1144 DOOR_GFX_PAGEX6+ED_BUTTON_ELEM_XPOS,
1145 DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS,
1146 4*ED_BUTTON_ELEM_XSIZE,5*ED_BUTTON_ELEM_YSIZE,
1147 DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS,
1148 DOOR_GFX_PAGEY1+ED_BUTTON_EUP_Y2POS);
1150 for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1152 if (i < elements_in_list)
1153 graphic = el2gfx(editor_element[i + element_shift]);
1155 graphic = GFX_LEERRAUM;
1157 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1158 DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS+3 +
1159 (i%MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
1160 DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS+3 +
1161 (i/MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
1165 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1166 DOOR_GFX_PAGEX1+ED_WIN_MB_LEFT_XPOS,
1167 DOOR_GFX_PAGEY1+ED_WIN_MB_LEFT_YPOS,
1168 el2gfx(new_element1));
1169 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1170 DOOR_GFX_PAGEX1+ED_WIN_MB_MIDDLE_XPOS,
1171 DOOR_GFX_PAGEY1+ED_WIN_MB_MIDDLE_YPOS,
1172 el2gfx(new_element2));
1173 DrawMiniGraphicExt(pix[PIX_DB_DOOR],gc,
1174 DOOR_GFX_PAGEX1+ED_WIN_MB_RIGHT_XPOS,
1175 DOOR_GFX_PAGEY1+ED_WIN_MB_RIGHT_YPOS,
1176 el2gfx(new_element3));
1177 DrawTextExt(pix[PIX_DB_DOOR],gc,
1178 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS,
1179 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1180 int2str(level_nr,2),FS_SMALL,FC_SPECIAL1);
1181 XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1182 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+3,
1183 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1185 DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS,
1186 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1187 XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1188 DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+14,
1189 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
1191 DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS+9,
1192 DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
1194 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1195 DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1197 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1199 /* draw bigger door */
1200 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1205 /* draw new control window */
1206 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
1207 DOOR_GFX_PAGEX8, 236,
1211 redraw_mask |= REDRAW_ALL;
1213 OpenDoor(DOOR_OPEN_1);
1215 if (!level_editor_gadgets_created)
1216 CreateLevelEditorGadgets();
1218 MapControlButtons();
1221 MapMainDrawingArea();
1224 DrawDrawingWindow();
1228 OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
1232 void DrawControlWindow()
1237 UnmapLevelEditorWindowGadgets();
1239 /* Inhalt der Mampfer */
1240 DrawText(ED_COUNT_GADGET_XPOS+1,SY+6,
1241 "Contents of a smashed cruncher:",FS_SMALL,FC_YELLOW);
1242 for(i=0;i<4;i++) for(y=0;y<4;y++) for(x=0;x<4;x++)
1244 DrawMiniElement(1+5*i+x,2+y,EL_ERDREICH);
1245 XFillRectangle(display,drawto,gc,
1246 SX+(1+5*i)*MINI_TILEX+MINI_TILEX/2-1,
1247 SY+(2)*MINI_TILEY+MINI_TILEY/2-1,
1248 3*MINI_TILEX+2,3*MINI_TILEY+2);
1250 XCopyArea(display,drawto,drawto,gc,
1251 SX+1*MINI_TILEX,SY+2*MINI_TILEY,
1252 4*5*MINI_TILEX,5*MINI_TILEY,
1253 SX+1*MINI_TILEX-MINI_TILEX/2,SY+2*MINI_TILEY-MINI_TILEY/2);
1256 for(y=0;y<3;y++) for(x=0;x<3;x++)
1257 DrawMiniElement(1+5*i+x,2+y,level.mampfer_inhalt[i][x][y]);
1259 DrawText(SX+MINI_TILEX+(5*i+1)*MINI_TILEX+1,
1260 SY+2*MINI_TILEY+(4)*MINI_TILEY-4,
1261 int2str(i+1,1),FS_SMALL,FC_YELLOW);
1264 /* Inhalt der Amöbe */
1265 for(y=0;y<2;y++) for(x=0;x<2;x++)
1267 DrawMiniElement(29+x,26+y,EL_ERDREICH);
1268 XFillRectangle(display,drawto,gc,
1269 SX+29*MINI_TILEX+MINI_TILEX/2-1,
1270 SY+26*MINI_TILEY+MINI_TILEY/2-1,
1271 MINI_TILEX+2,MINI_TILEY+2);
1273 XCopyArea(display,drawto,drawto,gc,
1274 SX+29*MINI_TILEX,SY+26*MINI_TILEY,
1275 3*MINI_TILEX,3*MINI_TILEY,
1276 SX+29*MINI_TILEX-MINI_TILEX/2,SY+26*MINI_TILEY-MINI_TILEY/2);
1277 DrawMiniElement(29,26,level.amoebe_inhalt);
1279 for(i=0;i<11+3+2;i++)
1281 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1282 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1283 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1284 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1285 ED_COUNT_GADGET_XPOS,
1286 ED_COUNT_GADGET_YPOS+i*ED_COUNT_GADGET_YSIZE);
1289 DrawText(ED_COUNT_VALUE_XPOS,
1290 ED_COUNT_VALUE_YPOS+i*ED_COUNT_GADGET_YSIZE,
1291 int2str(level.score[i],3),FS_SMALL,FC_YELLOW);
1293 DrawText(ED_COUNT_VALUE_XPOS,
1294 ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1295 int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1297 DrawText(ED_COUNT_VALUE_XPOS,
1298 ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1299 int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1301 DrawText(ED_COUNT_VALUE_XPOS,
1302 ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1303 int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1305 DrawText(ED_COUNT_VALUE_XPOS,
1306 ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1307 int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1309 DrawText(ED_COUNT_VALUE_XPOS,
1310 ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1311 int2str(level.time,3),FS_SMALL,FC_YELLOW);
1314 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+0*ED_COUNT_TEXT_YSIZE,
1315 "Score for Emerald",FS_SMALL,FC_YELLOW);
1316 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+1*ED_COUNT_TEXT_YSIZE,
1317 "Score for Diamond",FS_SMALL,FC_YELLOW);
1318 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+2*ED_COUNT_TEXT_YSIZE,
1319 "Score for smashing a Bug",FS_SMALL,FC_YELLOW);
1320 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+3*ED_COUNT_TEXT_YSIZE,
1321 "Score for smashing a Spaceship",FS_SMALL,FC_YELLOW);
1322 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+4*ED_COUNT_TEXT_YSIZE,
1323 "Score for smashing a Cruncher",FS_SMALL,FC_YELLOW);
1324 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+5*ED_COUNT_TEXT_YSIZE,
1325 "Score for smashing an Alien",FS_SMALL,FC_YELLOW);
1326 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+6*ED_COUNT_TEXT_YSIZE,
1327 "Score for smashing a Pacman",FS_SMALL,FC_YELLOW);
1328 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+7*ED_COUNT_TEXT_YSIZE,
1329 "Score for cracking a nut",FS_SMALL,FC_YELLOW);
1330 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+8*ED_COUNT_TEXT_YSIZE,
1331 "Score for dynamite",FS_SMALL,FC_YELLOW);
1332 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+9*ED_COUNT_TEXT_YSIZE,
1333 "Score for key",FS_SMALL,FC_YELLOW);
1334 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+10*ED_COUNT_TEXT_YSIZE,
1335 "Score for each 10 seconds left",FS_SMALL,FC_YELLOW);
1336 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+11*ED_COUNT_TEXT_YSIZE,
1337 "Speed of the amoeba / Content",FS_SMALL,FC_YELLOW);
1338 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+12*ED_COUNT_TEXT_YSIZE,
1339 "Time for magic wall",FS_SMALL,FC_YELLOW);
1340 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+13*ED_COUNT_TEXT_YSIZE,
1341 "Time for wheel",FS_SMALL,FC_YELLOW);
1342 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+14*ED_COUNT_TEXT_YSIZE,
1343 "Emeralds needed in this level",FS_SMALL,FC_YELLOW);
1344 DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+15*ED_COUNT_TEXT_YSIZE,
1345 "Time available for this level",FS_SMALL,FC_YELLOW);
1347 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1348 DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS,
1349 DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1350 ED_WIN_COUNT_XSIZE,ED_WIN_COUNT_YSIZE,
1351 ED_COUNT_GADGET_XPOS,
1352 ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1354 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1355 DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS+3+2*FONT2_XSIZE,
1356 DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
1357 ED_WIN_COUNT_XSIZE-3-2*FONT2_XSIZE,ED_WIN_COUNT_YSIZE,
1358 ED_COUNT_GADGET_XPOS+3+i*FONT2_XSIZE,
1359 ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
1360 DrawText(ED_COUNT_GADGET_XPOS+5,
1361 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1362 level.name,FS_SMALL,FC_YELLOW);
1363 DrawText(ED_COUNT_GADGET_XPOS+(30+3)*FONT2_XSIZE-5,
1364 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1365 "Title",FS_SMALL,FC_YELLOW);
1367 DrawText(ED_SIZE_GADGET_XPOS,ED_SIZE_GADGET_YPOS-18,
1368 "Playfield size:",FS_SMALL,FC_YELLOW);
1369 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1370 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1371 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1372 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1373 ED_SIZE_GADGET_XPOS,
1374 ED_SIZE_GADGET_YPOS+0*ED_COUNT_GADGET_YSIZE);
1375 XCopyArea(display,pix[PIX_DOOR],drawto,gc,
1376 DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
1377 DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
1378 DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
1379 ED_SIZE_GADGET_XPOS,
1380 ED_SIZE_GADGET_YPOS+1*ED_COUNT_GADGET_YSIZE);
1381 DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+0*ED_SIZE_TEXT_YSIZE,
1382 "Width",FS_SMALL,FC_YELLOW);
1383 DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+1*ED_SIZE_TEXT_YSIZE,
1384 "Height",FS_SMALL,FC_YELLOW);
1385 DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1386 int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1387 DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1388 int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1391 void AdjustLevelScrollPosition()
1393 if (level_xpos < -1)
1395 if (level_xpos > lev_fieldx - ED_FIELDX + 1)
1396 level_xpos = lev_fieldx - ED_FIELDX + 1;
1397 if (lev_fieldx < ED_FIELDX - 2)
1400 if (level_ypos < -1)
1402 if (level_ypos > lev_fieldy - ED_FIELDY + 1)
1403 level_ypos = lev_fieldy - ED_FIELDY + 1;
1404 if (lev_fieldy < ED_FIELDY - 2)
1408 static void PickDrawingElement(int button, int element)
1410 if (button < 1 || button > 3)
1415 new_element1 = element;
1416 DrawMiniGraphicExt(drawto, gc,
1417 DX + ED_WIN_MB_LEFT_XPOS,
1418 DY + ED_WIN_MB_LEFT_YPOS,
1419 el2gfx(new_element1));
1421 else if (button == 2)
1423 new_element2 = element;
1424 DrawMiniGraphicExt(drawto, gc,
1425 DX + ED_WIN_MB_MIDDLE_XPOS,
1426 DY + ED_WIN_MB_MIDDLE_YPOS,
1427 el2gfx(new_element2));
1431 new_element3 = element;
1432 DrawMiniGraphicExt(drawto, gc,
1433 DX + ED_WIN_MB_RIGHT_XPOS,
1434 DY + ED_WIN_MB_RIGHT_YPOS,
1435 el2gfx(new_element3));
1438 redraw_mask |= REDRAW_DOOR_1;
1441 void LevelEd(int mx, int my, int button)
1443 static int last_button = 0;
1444 static int in_field_pressed = FALSE;
1445 static boolean use_floodfill = FALSE;
1449 int x = (mx-SX)/MINI_TILEX;
1450 int y = (my-SY)/MINI_TILEY;
1454 HandlePressedControlButtons();
1455 HandleDrawingFunctions(mx, my, button);
1458 if (use_floodfill) /********** FLOOD FILL **********/
1466 if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
1471 if (x>lev_fieldx || y>lev_fieldy ||
1472 (x==0 && level_xpos<0) ||
1473 (x==ED_FIELDX-1 && level_xpos>lev_fieldx-ED_FIELDX) ||
1474 (y==0 && level_ypos<0) ||
1475 (y==ED_FIELDY-1 && level_ypos>lev_fieldy-ED_FIELDY))
1478 from_x = x+level_xpos;
1479 from_y = y+level_ypos;
1480 fill_element = (button==1 ? new_element1 :
1481 button==2 ? new_element2 :
1482 button==3 ? new_element3 : 0);
1484 FloodFill(from_x,from_y,fill_element);
1485 DrawMiniLevel(level_xpos,level_ypos);
1488 use_floodfill = FALSE;
1489 CloseDoor(DOOR_CLOSE_1);
1490 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
1499 else /********** EDIT/CTRL-FENSTER **********/
1501 static unsigned long choice_delay = 0;
1502 int choice = CheckElemButtons(mx,my,button);
1503 int elem_pos = choice-ED_BUTTON_ELEM;
1505 if (((choice == ED_BUTTON_EUP && element_shift>0) ||
1506 (choice == ED_BUTTON_EDOWN &&
1507 element_shift<elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)) &&
1508 DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1510 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
1514 step = (button==1 ? MAX_ELEM_X : button==2 ? 5*MAX_ELEM_X :
1516 element_shift += (choice==ED_BUTTON_EUP ? -step : step);
1518 step = step * MAX_ELEM_X * (choice == ED_BUTTON_EUP ? -1 : +1);
1519 element_shift += step;
1522 if (element_shift<0)
1524 if (element_shift>elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)
1525 element_shift = elements_in_list-MAX_ELEM_X*MAX_ELEM_Y;
1526 if (element_shift % MAX_ELEM_X)
1527 element_shift += MAX_ELEM_X-(element_shift % MAX_ELEM_X);
1529 for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
1530 DrawElemButton(i+2,ED_BUTTON_RELEASED);
1532 else if (elem_pos>=0 && elem_pos<MAX_ELEM_X*MAX_ELEM_Y)
1536 if (elem_pos+element_shift < elements_in_list)
1537 new_element = editor_element[elem_pos+element_shift];
1539 new_element = EL_LEERRAUM;
1541 PickDrawingElement(last_button, new_element);
1543 if (!HAS_CONTENT(properties_element))
1545 properties_element = new_element;
1546 if (edit_mode == ED_MODE_PROPERTIES)
1547 DrawPropertiesWindow();
1551 if (edit_mode == ED_MODE_DRAWING) /********** EDIT-FENSTER **********/
1558 switch(CheckEditButtons(mx,my,button))
1560 case ED_BUTTON_CTRL:
1561 CloseDoor(DOOR_CLOSE_2);
1562 DrawControlWindow();
1563 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1564 DOOR_GFX_PAGEX4,DOOR_GFX_PAGEY1+80,
1566 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1567 OpenDoor(DOOR_OPEN_2);
1568 edit_mode = ED_MODE_INFO;
1570 case ED_BUTTON_FILL:
1571 Request("Caution ! Flood fill mode ! Choose area !",REQ_OPEN);
1572 use_floodfill = TRUE;
1575 case ED_BUTTON_LEFT:
1578 if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1580 if (lev_fieldx<ED_FIELDX-2)
1583 level_xpos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
1587 ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_RIGHT);
1589 DrawMiniLevel(level_xpos,level_ypos);
1592 case ED_BUTTON_RIGHT:
1593 if (level_xpos<=lev_fieldx-ED_FIELDX)
1595 if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1597 if (lev_fieldx<ED_FIELDX-2)
1600 level_xpos += (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
1601 if (level_xpos>lev_fieldx-ED_FIELDX+1)
1602 level_xpos = lev_fieldx-ED_FIELDX+1;
1604 ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_LEFT);
1606 DrawMiniLevel(level_xpos,level_ypos);
1612 if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1614 if (lev_fieldy<ED_FIELDY-2)
1617 level_ypos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
1621 ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_DOWN);
1623 DrawMiniLevel(level_xpos,level_ypos);
1626 case ED_BUTTON_DOWN:
1627 if (level_ypos<=lev_fieldy-ED_FIELDY)
1629 if (!DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1631 if (lev_fieldy<ED_FIELDY-2)
1634 level_ypos += (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
1635 if (level_ypos>lev_fieldy-ED_FIELDY+1)
1636 level_ypos = lev_fieldy-ED_FIELDY+1;
1638 ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_UP);
1640 DrawMiniLevel(level_xpos,level_ypos);
1653 if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
1657 if (button && !motion_status)
1658 in_field_pressed = TRUE;
1660 if (!button || !in_field_pressed || button<1 || button>3 ||
1661 (y==0 && level_ypos<0) ||
1662 (y==ED_FIELDY-1 && level_ypos>lev_fieldy-ED_FIELDY) ||
1663 (x==0 && level_xpos<0) ||
1664 (x==ED_FIELDX-1 && level_xpos>lev_fieldx-ED_FIELDX) ||
1665 x>lev_fieldx || y>lev_fieldy)
1668 new_element = (button==1 ? new_element1 :
1669 button==2 ? new_element2 :
1670 button==3 ? new_element3 : 0);
1672 if (new_element != Feld[x+level_xpos][y+level_ypos])
1674 if (new_element==EL_SPIELFIGUR) /* Jeder nur EINE Figur bitte... */
1678 for(x=0;x<lev_fieldx;x++) for(y=0;y<lev_fieldy;y++)
1680 if (Feld[x][y]==EL_SPIELFIGUR || Feld[x][y]==EL_SPIELER1)
1682 Feld[x][y] = EL_LEERRAUM;
1683 if (x-level_xpos>=0 && x-level_xpos<ED_FIELDX &&
1684 y-level_ypos>=0 && y-level_ypos<ED_FIELDY)
1685 DrawMiniElement(x-level_xpos,y-level_ypos,EL_LEERRAUM);
1690 Feld[x+level_xpos][y+level_ypos] = new_element;
1691 DrawMiniElement(x,y,new_element);
1694 else if (!motion_status) /* Mauszeiger nicht im Level-Feld */
1695 in_field_pressed = FALSE;
1702 else if (edit_mode == ED_MODE_INFO)/********** KONTROLL-FENSTER **********/
1704 int choice = CheckCountButtons(mx,my,button);
1705 int step = (button==1 ? 1 : button==2 ? 5 : button==3 ? 10 : 0);
1707 if (choice >= 0 && choice < 36 &&
1708 DelayReached(&choice_delay, GADGET_FRAME_DELAY))
1717 level.score[choice] += step;
1718 if (level.score[choice]<0)
1719 level.score[choice] = 0;
1720 else if (level.score[choice]>255)
1721 level.score[choice] = 255;
1723 else if (choice==11)
1725 level.tempo_amoebe += step;
1726 if (level.tempo_amoebe<0)
1727 level.tempo_amoebe = 0;
1728 else if (level.tempo_amoebe>255)
1729 level.tempo_amoebe = 255;
1731 else if (choice==12)
1733 level.dauer_sieb += step;
1734 if (level.dauer_sieb<0)
1735 level.dauer_sieb = 0;
1736 else if (level.dauer_sieb>255)
1737 level.dauer_sieb = 255;
1739 else if (choice==13)
1741 level.dauer_ablenk += step;
1742 if (level.dauer_ablenk<0)
1743 level.dauer_ablenk = 0;
1744 else if (level.dauer_ablenk>255)
1745 level.dauer_ablenk = 255;
1747 else if (choice==14)
1749 level.edelsteine += step;
1750 if (level.edelsteine<0)
1751 level.edelsteine = 0;
1752 else if (level.edelsteine>999)
1753 level.edelsteine = 999;
1755 else if (choice==15)
1760 else if (level.time>999)
1763 else if (choice==16)
1766 if (lev_fieldx<MIN_LEV_FIELDX)
1767 lev_fieldx = MIN_LEV_FIELDX;
1768 else if (lev_fieldx>MAX_LEV_FIELDX)
1769 lev_fieldx = MAX_LEV_FIELDX;
1770 level.fieldx = lev_fieldx;
1772 else if (choice==17)
1775 if (lev_fieldy<MIN_LEV_FIELDY)
1776 lev_fieldy = MIN_LEV_FIELDY;
1777 else if (lev_fieldy>MAX_LEV_FIELDY)
1778 lev_fieldy = MAX_LEV_FIELDY;
1779 level.fieldy = lev_fieldy;
1783 DrawText(ED_COUNT_VALUE_XPOS,
1784 ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
1785 int2str(level.score[choice],3),FS_SMALL,FC_YELLOW);
1786 else if (choice==11)
1787 DrawText(ED_COUNT_VALUE_XPOS,
1788 ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
1789 int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
1790 else if (choice==12)
1791 DrawText(ED_COUNT_VALUE_XPOS,
1792 ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
1793 int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
1794 else if (choice==13)
1795 DrawText(ED_COUNT_VALUE_XPOS,
1796 ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
1797 int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
1798 else if (choice==14)
1799 DrawText(ED_COUNT_VALUE_XPOS,
1800 ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
1801 int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
1802 else if (choice==15)
1803 DrawText(ED_COUNT_VALUE_XPOS,
1804 ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
1805 int2str(level.time,3),FS_SMALL,FC_YELLOW);
1806 else if (choice==16)
1807 DrawText(ED_SIZE_VALUE_XPOS,
1808 ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
1809 int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
1810 else if (choice==17)
1811 DrawText(ED_SIZE_VALUE_XPOS,
1812 ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
1813 int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
1815 redraw_mask &= ~REDRAW_FIELD;
1817 XCopyArea(display,drawto,window,gc,
1818 ED_COUNT_VALUE_XPOS,
1819 ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
1820 3*FONT2_XSIZE,FONT2_YSIZE,
1821 ED_COUNT_VALUE_XPOS,
1822 ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE);
1824 XCopyArea(display,drawto,window,gc,
1826 ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE,
1827 3*FONT2_XSIZE,FONT2_YSIZE,
1829 ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE);
1837 switch(CheckCtrlButtons(mx,my,button))
1839 case ED_BUTTON_EDIT:
1840 CloseDoor(DOOR_CLOSE_2);
1841 AdjustLevelScrollPosition();
1842 DrawMiniLevel(level_xpos,level_ypos);
1843 XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1844 DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
1846 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1847 OpenDoor(DOOR_OPEN_2);
1848 edit_mode = ED_MODE_DRAWING;
1850 case ED_BUTTON_CLEAR:
1851 if (Request("Are you sure to clear this level ?",REQ_ASK))
1853 for(x=0;x<MAX_LEV_FIELDX;x++)
1854 for(y=0;y<MAX_LEV_FIELDY;y++)
1855 Feld[x][y] = EL_ERDREICH;
1856 DrawMiniLevel(level_xpos,level_ypos);
1859 case ED_BUTTON_UNDO:
1860 if (leveldir[leveldir_nr].readonly ||
1861 Request("Exit without saving ?",REQ_ASK | REQ_STAY_OPEN))
1863 CloseDoor(DOOR_CLOSE_ALL);
1864 game_status=MAINMENU;
1869 CloseDoor(DOOR_CLOSE_1);
1870 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
1873 case ED_BUTTON_EXIT:
1875 int figur_vorhanden = FALSE;
1877 if (leveldir[leveldir_nr].readonly)
1879 Request("This level is read only !",REQ_CONFIRM);
1883 for(y=0;y<lev_fieldy;y++)
1884 for(x=0;x<lev_fieldx;x++)
1885 if (Feld[x][y] == EL_SPIELFIGUR ||
1886 Feld[x][y] == EL_SPIELER1 ||
1887 Feld[x][y] == EL_SP_MURPHY)
1888 figur_vorhanden = TRUE;
1890 if (!figur_vorhanden)
1891 Request("No Level without Gregor Mc Duffin please !",
1895 if (Request("Save this level and kill the old ?",
1896 REQ_ASK | REQ_STAY_OPEN))
1898 for(x=0;x<lev_fieldx;x++)
1899 for(y=0;y<lev_fieldy;y++)
1900 Ur[x][y]=Feld[x][y];
1901 SaveLevel(level_nr);
1903 CloseDoor(DOOR_CLOSE_ALL);
1904 game_status=MAINMENU;
1917 if (mx>=ED_COUNT_GADGET_XPOS &&
1918 mx<ED_COUNT_GADGET_XPOS+31*FONT2_XSIZE+10 &&
1919 my>=ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE &&
1920 my<ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE+ED_WIN_COUNT_YSIZE)
1925 DrawText(ED_COUNT_GADGET_XPOS+5,
1926 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1927 level.name,FS_SMALL,FC_GREEN);
1928 DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
1929 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1930 "<",FS_SMALL,FC_RED);
1937 name_typing = FALSE;
1938 DrawText(ED_COUNT_GADGET_XPOS+5,
1939 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1940 level.name,FS_SMALL,FC_YELLOW);
1941 DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
1942 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
1943 " ",FS_SMALL,FC_RED);
1947 if (mx>=SX+29*MINI_TILEX && mx<SX+30*MINI_TILEX &&
1948 my>=SY+26*MINI_TILEY && my<SY+27*MINI_TILEY)
1952 if (!button || button<1 || button>3)
1955 new_element = (button==1 ? new_element1 :
1956 button==2 ? new_element2 :
1957 button==3 ? new_element3 : 0);
1959 if (new_element != level.amoebe_inhalt)
1961 level.amoebe_inhalt = new_element;
1962 DrawMiniElement(29,26,new_element);
1966 if (mx>=SX+1*MINI_TILEX && mx<SX+(1+4*5)*MINI_TILEX &&
1967 my>=SY+2*MINI_TILEY && my<SY+(2+3)*MINI_TILEY)
1969 int x = (mx-SX-1*MINI_TILEX)/MINI_TILEX;
1970 int y = (my-SY-2*MINI_TILEY)/MINI_TILEY;
1975 if (i>=0 && i<43 && x>=0 && x<3 && y>=0 && y<3)
1977 if (button && !motion_status)
1978 in_field_pressed = TRUE;
1980 if (!button || !in_field_pressed || button<1 || button>3)
1983 new_element = (button==1 ? new_element1 :
1984 button==2 ? new_element2 :
1985 button==3 ? new_element3 : 0);
1987 if (new_element != level.mampfer_inhalt[i][x][y])
1989 level.mampfer_inhalt[i][x][y] = new_element;
1990 DrawMiniElement(1+5*i+x,2+y,new_element);
1993 else if (!motion_status)/* Mauszeiger nicht im Cruncher-Feld */
1994 in_field_pressed = FALSE;
1996 else if (!motion_status) /* Mauszeiger nicht im Cruncher-Feld */
1997 in_field_pressed = FALSE;
2001 last_button = button;
2006 void LevelNameTyping(KeySym key)
2008 unsigned char ascii = 0;
2009 int len = strlen(level.name);
2014 if (key>=XK_A && key<=XK_Z)
2015 ascii = 'A'+(char)(key-XK_A);
2016 else if (key>=XK_a && key<=XK_z)
2017 ascii = 'a'+(char)(key-XK_a);
2018 else if (key>=XK_0 && key<=XK_9)
2019 ascii = '0'+(char)(key-XK_0);
2021 else if (key>=XK_space && key<=XK_at)
2022 ascii = ' '+(char)(key-XK_space);
2023 else if (key==XK_Adiaeresis)
2025 else if (key==XK_Odiaeresis)
2027 else if (key==XK_Udiaeresis)
2029 else if (key==XK_adiaeresis)
2031 else if (key==XK_odiaeresis)
2033 else if (key==XK_udiaeresis)
2035 else if (key==XK_underscore)
2039 if (ascii && len<MAX_LEVNAMLEN-2)
2041 level.name[len] = ascii;
2042 level.name[len+1] = 0;
2045 DrawTextExt(drawto,gc,
2046 ED_COUNT_GADGET_XPOS+5,
2047 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2048 level.name,FS_SMALL,FC_GREEN);
2049 DrawTextExt(window,gc,
2050 ED_COUNT_GADGET_XPOS+5,
2051 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2052 level.name,FS_SMALL,FC_GREEN);
2053 DrawTextExt(drawto,gc,
2054 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2055 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2056 "<",FS_SMALL,FC_RED);
2057 DrawTextExt(window,gc,
2058 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2059 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2060 "<",FS_SMALL,FC_RED);
2062 else if ((key==XK_Delete || key==XK_BackSpace) && len>0)
2064 level.name[len-1] = 0;
2067 DrawTextExt(drawto,gc,
2068 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2069 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2070 "< ",FS_SMALL,FC_GREEN);
2071 DrawTextExt(window,gc,
2072 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2073 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2074 "< ",FS_SMALL,FC_GREEN);
2076 else if (key==XK_Return)
2078 DrawTextExt(drawto,gc,
2079 ED_COUNT_GADGET_XPOS+5,
2080 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2081 level.name,FS_SMALL,FC_YELLOW);
2082 DrawTextExt(window,gc,
2083 ED_COUNT_GADGET_XPOS+5,
2084 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2085 level.name,FS_SMALL,FC_YELLOW);
2086 DrawTextExt(drawto,gc,
2087 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2088 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2089 " ",FS_SMALL,FC_YELLOW);
2090 DrawTextExt(window,gc,
2091 ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
2092 ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
2093 " ",FS_SMALL,FC_YELLOW);
2095 name_typing = FALSE;
2099 static void DrawCounterValueField(int counter_id, int value)
2101 int x = SX + counterbutton_info[counter_id].x + ED_WIN_COUNT_XPOS;
2102 int y = SY + counterbutton_info[counter_id].y;
2104 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2105 DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS,
2106 DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS,
2107 ED_WIN_COUNT_XSIZE, ED_WIN_COUNT_YSIZE,
2110 DrawText(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2111 int2str(value, 3), FS_SMALL, FC_YELLOW);
2114 static void DrawDrawingWindow()
2117 UnmapLevelEditorWindowGadgets();
2118 MapMainDrawingArea();
2119 AdjustLevelScrollPosition();
2120 DrawMiniLevel(level_xpos, level_ypos);
2123 static void DrawElementContentAreas()
2125 int *num_areas = &MampferMax;
2126 int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX;
2127 int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY;
2128 int area_sx = SX + ED_AREA_ELEMCONT_XPOS;
2129 int area_sy = SY + ED_AREA_ELEMCONT_YPOS;
2132 for (i=0; i<MAX_ELEMCONT; i++)
2135 ElementContent[i][x][y] = level.mampfer_inhalt[i][x][y];
2137 for (i=0; i<MAX_ELEMCONT; i++)
2138 UnmapDrawingArea(ED_CTRL_ID_ELEMCONT_0 + i);
2140 /* display counter to choose number of element content areas */
2141 gadget_areas_value = num_areas;
2142 DrawCounterValueField(ED_COUNTER_ELEMCONT, *gadget_areas_value);
2143 x = counterbutton_info[ED_COUNTER_ELEMCONT].x + DXSIZE;
2144 y = counterbutton_info[ED_COUNTER_ELEMCONT].y;
2145 DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2146 FC_YELLOW, "number of content areas");
2147 MapCounterButtons(ED_COUNTER_ELEMCONT);
2149 /* delete content areas in case of reducing number of them */
2150 XFillRectangle(display, backbuffer, gc,
2151 SX, area_sy - MINI_TILEX,
2152 SXSIZE, 12 * MINI_TILEY);
2154 /* draw some decorative border for the objects */
2155 for (i=0; i<*num_areas; i++)
2159 DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2162 XFillRectangle(display, drawto, gc,
2163 area_sx + 5 * (i % 4) * MINI_TILEX + MINI_TILEX/2 - 1,
2164 area_sy + 6 * (i / 4) * MINI_TILEY + MINI_TILEY/2 - 1,
2165 3 * MINI_TILEX + 2, 3 * MINI_TILEY + 2);
2168 /* copy border to the right location */
2169 XCopyArea(display, drawto, drawto, gc,
2170 area_sx, area_sy, (5 * 4 + 1) * MINI_TILEX, 12 * MINI_TILEY,
2171 area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2173 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
2174 "Content", FS_SMALL, FC_YELLOW);
2175 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
2176 "when", FS_SMALL, FC_YELLOW);
2177 DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
2178 "smashed", FS_SMALL, FC_YELLOW);
2180 for (i=0; i<*num_areas; i++)
2184 DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
2185 ElementContent[i][x][y]);
2187 DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
2188 area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
2189 FC_YELLOW, "%d", i + 1);
2192 for (i=0; i<*num_areas; i++)
2193 MapDrawingArea(ED_CTRL_ID_ELEMCONT_0 + i);
2196 static void DrawAmoebaContentArea()
2198 int area_x = ED_AREA_ELEMCONT_XPOS / MINI_TILEX;
2199 int area_y = ED_AREA_ELEMCONT_YPOS / MINI_TILEY;
2200 int area_sx = SX + ED_AREA_ELEMCONT_XPOS;
2201 int area_sy = SY + ED_AREA_ELEMCONT_YPOS;
2204 ElementContent[0][0][0] = level.amoebe_inhalt;
2206 /* draw decorative border for the object */
2209 DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
2211 XFillRectangle(display, drawto, gc,
2212 area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
2213 MINI_TILEX + 2, MINI_TILEY + 2);
2215 /* copy border to the right location */
2216 XCopyArea(display, drawto, drawto, gc,
2217 area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
2218 area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
2220 DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba",
2221 FS_SMALL, FC_YELLOW);
2223 DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
2225 MapDrawingArea(ED_CTRL_ID_AMOEBA_CONTENT);
2228 #define TEXT_COLLECTING "Score for collecting"
2229 #define TEXT_SMASHING "Score for smashing"
2230 #define TEXT_CRACKING "Score for cracking"
2231 #define TEXT_SPEED "Speed of amoeba growth"
2232 #define TEXT_DURATION "Duration when activated"
2234 static void DrawPropertiesWindow()
2237 int num_elements_in_level;
2243 } elements_with_counter[] =
2245 { EL_EDELSTEIN, &level.score[0], TEXT_COLLECTING },
2246 { EL_EDELSTEIN_BD, &level.score[0], TEXT_COLLECTING },
2247 { EL_EDELSTEIN_GELB,&level.score[0], TEXT_COLLECTING },
2248 { EL_EDELSTEIN_ROT, &level.score[0], TEXT_COLLECTING },
2249 { EL_EDELSTEIN_LILA,&level.score[0], TEXT_COLLECTING },
2250 { EL_DIAMANT, &level.score[1], TEXT_COLLECTING },
2251 { EL_KAEFER_R, &level.score[2], TEXT_SMASHING },
2252 { EL_KAEFER_O, &level.score[2], TEXT_SMASHING },
2253 { EL_KAEFER_L, &level.score[2], TEXT_SMASHING },
2254 { EL_KAEFER_U, &level.score[2], TEXT_SMASHING },
2255 { EL_BUTTERFLY_R, &level.score[2], TEXT_SMASHING },
2256 { EL_BUTTERFLY_O, &level.score[2], TEXT_SMASHING },
2257 { EL_BUTTERFLY_L, &level.score[2], TEXT_SMASHING },
2258 { EL_BUTTERFLY_U, &level.score[2], TEXT_SMASHING },
2259 { EL_FLIEGER_R, &level.score[3], TEXT_SMASHING },
2260 { EL_FLIEGER_O, &level.score[3], TEXT_SMASHING },
2261 { EL_FLIEGER_L, &level.score[3], TEXT_SMASHING },
2262 { EL_FLIEGER_U, &level.score[3], TEXT_SMASHING },
2263 { EL_FIREFLY_R, &level.score[3], TEXT_SMASHING },
2264 { EL_FIREFLY_O, &level.score[3], TEXT_SMASHING },
2265 { EL_FIREFLY_L, &level.score[3], TEXT_SMASHING },
2266 { EL_FIREFLY_U, &level.score[3], TEXT_SMASHING },
2267 { EL_MAMPFER, &level.score[4], TEXT_SMASHING },
2268 { EL_MAMPFER2, &level.score[4], TEXT_SMASHING },
2269 { EL_ROBOT, &level.score[5], TEXT_SMASHING },
2270 { EL_PACMAN_R, &level.score[6], TEXT_SMASHING },
2271 { EL_PACMAN_O, &level.score[6], TEXT_SMASHING },
2272 { EL_PACMAN_L, &level.score[6], TEXT_SMASHING },
2273 { EL_PACMAN_U, &level.score[6], TEXT_SMASHING },
2274 { EL_KOKOSNUSS, &level.score[7], TEXT_CRACKING },
2275 { EL_DYNAMIT_AUS, &level.score[8], TEXT_COLLECTING },
2276 { EL_SCHLUESSEL1, &level.score[9], TEXT_COLLECTING },
2277 { EL_SCHLUESSEL2, &level.score[9], TEXT_COLLECTING },
2278 { EL_SCHLUESSEL3, &level.score[9], TEXT_COLLECTING },
2279 { EL_SCHLUESSEL4, &level.score[9], TEXT_COLLECTING },
2280 { EL_AMOEBE_NASS, &level.tempo_amoebe, TEXT_SPEED },
2281 { EL_AMOEBE_NORM, &level.tempo_amoebe, TEXT_SPEED },
2282 { EL_AMOEBE_VOLL, &level.tempo_amoebe, TEXT_SPEED },
2283 { EL_AMOEBE_BD, &level.tempo_amoebe, TEXT_SPEED },
2284 { EL_SIEB_INAKTIV, &level.dauer_sieb, TEXT_DURATION },
2285 { EL_ABLENK_AUS, &level.dauer_ablenk, TEXT_DURATION },
2290 UnmapLevelEditorWindowGadgets();
2292 /* draw some decorative border for the object */
2295 DrawMiniElement(2 + x , 2 + y, EL_ERDREICH);
2297 XFillRectangle(display, drawto, gc,
2298 SX + TILEX + MINI_TILEX/2 - 1,
2299 SY + TILEY + MINI_TILEY/2 - 1,
2300 TILEX + 2, TILEY + 2);
2302 /* copy border to the right location */
2303 XCopyArea(display, drawto, drawto, gc,
2304 SX + TILEX, SY + TILEY,
2305 2 * TILEX, 2 * TILEY,
2306 SX + TILEX - MINI_TILEX/2, SY + TILEY - MINI_TILEY/2);
2308 DrawGraphic(1, 1, el2gfx(properties_element));
2309 DrawText(SX + 3*TILEX, SY + 5*TILEY/4, "Element Properties",
2310 FS_SMALL, FC_YELLOW);
2312 num_elements_in_level = 0;
2313 for (y=0; y<lev_fieldy; y++)
2314 for (x=0; x<lev_fieldx; x++)
2315 if (Feld[x][y] == properties_element)
2316 num_elements_in_level++;
2318 DrawTextF(ED_PROPERTIES_XPOS, 5*TILEY, FC_YELLOW, "%d x contained in level",
2319 num_elements_in_level);
2321 /* check if there are elements where a score can be chosen for */
2322 for (i=0; elements_with_counter[i].element != -1; i++)
2324 if (elements_with_counter[i].element == properties_element)
2326 int x = counterbutton_info[ED_COUNTER_SCORE].x + DXSIZE;
2327 int y = counterbutton_info[ED_COUNTER_SCORE].y;
2329 gadget_score_value = elements_with_counter[i].counter_value;
2330 DrawCounterValueField(ED_COUNTER_SCORE, *gadget_score_value);
2331 DrawTextF(x + ED_COUNT_VALUE_XOFFSET, y + ED_COUNT_VALUE_YOFFSET,
2332 FC_YELLOW, elements_with_counter[i].text);
2333 MapCounterButtons(ED_COUNTER_SCORE);
2338 if (HAS_CONTENT(properties_element))
2340 if (IS_AMOEBOID(properties_element))
2341 DrawAmoebaContentArea();
2343 DrawElementContentAreas();
2346 /* TEST ONLY: level name text input gadget */
2347 MapTextInputGadget(ED_CTRL_ID_LEVEL_NAME);
2350 static void swap_numbers(int *i1, int *i2)
2358 static void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
2370 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
2372 int lx = sx + level_xpos;
2373 int ly = sy + level_ypos;
2375 DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element));
2378 Feld[lx][ly] = element;
2381 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
2382 int element, boolean change_level)
2384 if (from_y == to_y) /* horizontal line */
2390 swap_numbers(&from_x, &to_x);
2392 for (x=from_x; x<=to_x; x++)
2393 DrawLineElement(x, y, element, change_level);
2395 else if (from_x == to_x) /* vertical line */
2401 swap_numbers(&from_y, &to_y);
2403 for (y=from_y; y<=to_y; y++)
2404 DrawLineElement(x, y, element, change_level);
2406 else /* diagonal line */
2408 int len_x = ABS(to_x - from_x);
2409 int len_y = ABS(to_y - from_y);
2412 if (len_y < len_x) /* a < 1 */
2414 float a = (float)len_y / (float)len_x;
2417 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2419 for (x=0; x<=len_x; x++)
2421 int y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1);
2423 DrawLineElement(from_x + x, from_y + y, element, change_level);
2428 float a = (float)len_x / (float)len_y;
2431 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2433 for (y=0; y<=len_y; y++)
2435 int x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1);
2437 DrawLineElement(from_x + x, from_y + y, element, change_level);
2443 static void DrawRectangle(int from_x, int from_y, int to_x, int to_y,
2444 int element, boolean change_level)
2446 DrawLine(from_x, from_y, from_x, to_y, element, change_level);
2447 DrawLine(from_x, to_y, to_x, to_y, element, change_level);
2448 DrawLine(to_x, to_y, to_x, from_y, element, change_level);
2449 DrawLine(to_x, from_y, from_x, from_y, element, change_level);
2452 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
2453 int element, boolean change_level)
2458 swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
2460 for (y=from_y; y<=to_y; y++)
2461 DrawLine(from_x, y, to_x, y, element, change_level);
2464 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
2466 int from_sx, from_sy;
2470 swap_numbers(&from_x, &to_x);
2473 swap_numbers(&from_y, &to_y);
2475 from_sx = SX + from_x * MINI_TILEX;
2476 from_sy = SY + from_y * MINI_TILEY;
2477 to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
2478 to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
2480 XSetForeground(display, gc, WhitePixel(display, screen));
2482 XDrawLine(display, drawto, gc, from_sx, from_sy, to_sx, from_sy);
2483 XDrawLine(display, drawto, gc, to_sx, from_sy, to_sx, to_sy);
2484 XDrawLine(display, drawto, gc, to_sx, to_sy, from_sx, to_sy);
2485 XDrawLine(display, drawto, gc, from_sx, to_sy, from_sx, from_sy);
2487 XSetForeground(display, gc, BlackPixel(display, screen));
2489 if (from_x == to_x && from_y == to_y)
2490 MarkTileDirty(from_x/2, from_y/2);
2492 redraw_mask |= REDRAW_FIELD;
2495 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
2496 int element, boolean change_level)
2498 if (element == -1 || change_level)
2499 DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE);
2501 DrawAreaBorder(from_x, from_y, to_x, to_y);
2504 /* values for CopyBrushExt() */
2505 #define CB_AREA_TO_BRUSH 0
2506 #define CB_BRUSH_TO_LEVEL 1
2508 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, int mode)
2510 static short brush_buffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
2511 static int brush_from_x, brush_from_y;
2512 static int brush_to_x, brush_to_y;
2516 swap_numbers(&from_x, &to_x);
2519 swap_numbers(&from_y, &to_y);
2521 if (mode == CB_AREA_TO_BRUSH)
2523 for (y=from_y; y<=to_y; y++)
2524 for (x=from_x; x<=to_x; x++)
2525 brush_buffer[x][y] = Feld[x][y];
2527 brush_from_x = from_x;
2528 brush_from_y = from_y;
2534 for (y=brush_from_y; y<=brush_to_y; y++)
2535 for (x=brush_from_x; x<=brush_to_x; x++)
2536 Feld[x][y] = brush_buffer[x][y];
2537 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2541 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y)
2543 CopyBrushExt(from_x, from_y, to_x, to_y, CB_AREA_TO_BRUSH);
2547 static void CopyBrushToLevel()
2549 CopyBrushExt(0, 0, 0, 0, CB_BRUSH_TO_LEVEL);
2553 static void FloodFill(int from_x, int from_y, int fill_element)
2557 static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
2558 static int safety = 0;
2560 /* check if starting field still has the desired content */
2561 if (Feld[from_x][from_y] == fill_element)
2566 if (safety > lev_fieldx*lev_fieldy)
2567 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
2569 old_element = Feld[from_x][from_y];
2570 Feld[from_x][from_y] = fill_element;
2574 x = from_x + check[i][0];
2575 y = from_y + check[i][1];
2577 if (IN_LEV_FIELD(x,y) && Feld[x][y] == old_element)
2578 FloodFill(x, y, fill_element);
2584 /* values for DrawLevelText() modes */
2586 #define TEXT_SETCURSOR 1
2587 #define TEXT_WRITECHAR 2
2588 #define TEXT_BACKSPACE 3
2589 #define TEXT_NEWLINE 4
2592 static void DrawLevelText(int sx, int sy, char letter, int mode)
2594 static short delete_buffer[MAX_LEV_FIELDX];
2595 static int start_sx, start_sy;
2596 static int last_sx, last_sy;
2597 static boolean typing = FALSE;
2598 int letter_element = EL_CHAR_ASCII0 + letter;
2601 /* map lower case letters to upper case and convert special characters */
2602 if (letter >= 'a' && letter <= 'z')
2603 letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
2604 else if (letter == 'ä' || letter == 'Ä')
2605 letter_element = EL_CHAR_AE;
2606 else if (letter == 'ö' || letter == 'Ö')
2607 letter_element = EL_CHAR_OE;
2608 else if (letter == 'ü' || letter == 'Ü')
2609 letter_element = EL_CHAR_UE;
2610 else if (letter == '^')
2611 letter_element = EL_CHAR_COPY;
2613 letter_element = EL_CHAR_ASCII0 + letter;
2615 if (mode != TEXT_INIT)
2620 if (mode != TEXT_SETCURSOR)
2626 lx = last_sx + level_xpos;
2627 ly = last_sy + level_ypos;
2634 DrawLevelText(0, 0, 0, TEXT_END);
2637 start_sx = last_sx = sx;
2638 start_sy = last_sy = sy;
2639 DrawLevelText(sx, sy, 0, TEXT_SETCURSOR);
2642 case TEXT_SETCURSOR:
2643 DrawMiniElement(last_sx, last_sy, Feld[lx][ly]);
2644 DrawAreaBorder(sx, sy, sx, sy);
2649 case TEXT_WRITECHAR:
2650 if (letter_element >= EL_CHAR_START && letter_element <= EL_CHAR_END)
2652 delete_buffer[sx - start_sx] = Feld[lx][ly];
2653 Feld[lx][ly] = letter_element;
2655 if (sx + 1 < ED_FIELDX && lx + 1 < lev_fieldx)
2656 DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
2657 else if (sy + 1 < ED_FIELDY && ly + 1 < lev_fieldy)
2658 DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2660 DrawLevelText(0, 0, 0, TEXT_END);
2664 case TEXT_BACKSPACE:
2667 Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
2668 DrawMiniElement(sx - 1, sy, new_element3);
2669 DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
2674 if (sy + 1 < ED_FIELDY - 1 && ly + 1 < lev_fieldy - 1)
2675 DrawLevelText(start_sx, sy + 1, 0, TEXT_SETCURSOR);
2677 DrawLevelText(0, 0, 0, TEXT_END);
2681 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2682 DrawMiniElement(sx, sy, Feld[lx][ly]);
2691 static void CopyLevelToUndoBuffer(int mode)
2693 static boolean accumulated_undo = FALSE;
2694 boolean new_undo_buffer_position = TRUE;
2699 case UNDO_IMMEDIATE:
2700 accumulated_undo = FALSE;
2703 case UNDO_ACCUMULATE:
2704 if (accumulated_undo)
2705 new_undo_buffer_position = FALSE;
2706 accumulated_undo = TRUE;
2713 if (new_undo_buffer_position)
2715 /* new position in undo buffer ring */
2716 undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
2718 if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
2719 undo_buffer_steps++;
2722 for(x=0; x<lev_fieldx; x++)
2723 for(y=0; y<lev_fieldy; y++)
2724 UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
2727 printf("level saved to undo buffer\n");
2732 static void RandomPlacement(int button)
2737 new_element = (button == 1 ? new_element1 :
2738 button == 2 ? new_element2 :
2739 button == 3 ? new_element3 : 0);
2741 if (random_placement_method == RANDOM_USE_PERCENTAGE)
2743 for(x=0; x<lev_fieldx; x++)
2744 for(y=0; y<lev_fieldy; y++)
2745 if (RND(100) < random_placement_percentage)
2746 Feld[x][y] = new_element;
2750 int elements_left = random_placement_num_objects;
2752 while (elements_left > 0)
2754 x = RND(lev_fieldx);
2755 y = RND(lev_fieldy);
2757 if (Feld[x][y] != new_element)
2759 Feld[x][y] = new_element;
2765 DrawMiniLevel(level_xpos, level_ypos);
2766 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2769 void WrapLevel(int dx, int dy)
2771 int wrap_dx = lev_fieldx - dx;
2772 int wrap_dy = lev_fieldy - dy;
2775 for(x=0; x<lev_fieldx; x++)
2776 for(y=0; y<lev_fieldy; y++)
2777 FieldBackup[x][y] = Feld[x][y];
2779 for(x=0; x<lev_fieldx; x++)
2780 for(y=0; y<lev_fieldy; y++)
2782 FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
2784 DrawMiniLevel(level_xpos, level_ypos);
2785 CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
2788 static void HandleDrawingAreas(struct GadgetInfo *gi)
2790 static boolean started_inside_drawing_area = FALSE;
2791 static boolean draw_with_brush = FALSE;
2792 int id = gi->custom_id;
2793 boolean inside_drawing_area = !gi->event.off_borders;
2794 boolean button_press_event;
2795 boolean button_release_event;
2796 boolean draw_level = (id == ED_CTRL_ID_DRAWING_LEVEL);
2798 int button = gi->event.button;
2799 int sx = gi->event.x, sy = gi->event.y;
2800 int min_sx = 0, min_sy = 0;
2801 int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
2803 int min_lx = 0, min_ly = 0;
2804 int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
2808 if (edit_mode != ED_MODE_DRAWING)
2812 button_press_event = (gi->event.type == GD_EVENT_PRESSED);
2813 button_release_event = (gi->event.type == GD_EVENT_RELEASED);
2815 /* make sure to stay inside drawing area boundaries */
2816 sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
2817 sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
2821 /* get positions inside level field */
2822 lx = sx + level_xpos;
2823 ly = sy + level_ypos;
2825 /* make sure to stay inside level field boundaries */
2826 lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
2827 ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
2829 /* correct drawing area positions accordingly */
2830 sx = lx - level_xpos;
2831 sy = ly - level_ypos;
2834 if (button_press_event)
2835 started_inside_drawing_area = inside_drawing_area;
2837 if (!started_inside_drawing_area)
2840 if (!button && !button_release_event)
2843 new_element = (button == 1 ? new_element1 :
2844 button == 2 ? new_element2 :
2845 button == 3 ? new_element3 : 0);
2847 if (!draw_level && drawing_function != ED_CTRL_ID_SINGLE_ITEMS)
2850 switch (drawing_function)
2852 case ED_CTRL_ID_SINGLE_ITEMS:
2855 if (button_release_event)
2856 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2861 if (new_element != Feld[lx][ly])
2863 if (new_element == EL_SPIELFIGUR)
2865 /* remove player at old position */
2866 for(y=0; y<lev_fieldy; y++)
2868 for(x=0; x<lev_fieldx; x++)
2870 if (Feld[x][y] == EL_SPIELFIGUR || Feld[x][y] == EL_SPIELER1)
2872 Feld[x][y] = EL_LEERRAUM;
2873 if (x - level_xpos >= 0 && x - level_xpos < ED_FIELDX &&
2874 y - level_ypos >= 0 && y - level_ypos < ED_FIELDY)
2875 DrawMiniElement(x - level_xpos, y - level_ypos,
2882 Feld[lx][ly] = new_element;
2883 DrawMiniElement(sx, sy, new_element);
2888 DrawMiniGraphicExt(drawto, gc,
2889 gi->x + sx * MINI_TILEX,
2890 gi->y + sy * MINI_TILEY,
2891 el2gfx(new_element));
2892 DrawMiniGraphicExt(window, gc,
2893 gi->x + sx * MINI_TILEX,
2894 gi->y + sy * MINI_TILEY,
2895 el2gfx(new_element));
2897 if (id == ED_CTRL_ID_AMOEBA_CONTENT)
2898 level.amoebe_inhalt = new_element;
2899 else if (id >= ED_CTRL_ID_ELEMCONT_0 && id <= ED_CTRL_ID_ELEMCONT_7)
2900 level.mampfer_inhalt[id - ED_CTRL_ID_ELEMCONT_0][sx][sy] =
2905 case ED_CTRL_ID_CONNECTED_ITEMS:
2907 static int last_sx = -1;
2908 static int last_sy = -1;
2910 if (button_release_event)
2911 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2915 if (!button_press_event)
2916 DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
2924 case ED_CTRL_ID_LINE:
2925 case ED_CTRL_ID_RECTANGLE:
2926 case ED_CTRL_ID_FILLED_BOX:
2927 case ED_CTRL_ID_BRUSH:
2929 static int last_sx = -1;
2930 static int last_sy = -1;
2931 static int start_sx = -1;
2932 static int start_sy = -1;
2933 void (*draw_func)(int, int, int, int, int, boolean);
2935 if (drawing_function == ED_CTRL_ID_LINE)
2936 draw_func = DrawLine;
2937 else if (drawing_function == ED_CTRL_ID_RECTANGLE)
2938 draw_func = DrawRectangle;
2939 else if (drawing_function == ED_CTRL_ID_FILLED_BOX)
2940 draw_func = DrawFilledBox;
2942 draw_func = SelectArea;
2944 if (button_press_event)
2946 draw_func(sx, sy, sx, sy, new_element, FALSE);
2947 start_sx = last_sx = sx;
2948 start_sy = last_sy = sy;
2950 else if (button_release_event)
2952 draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
2953 if (drawing_function == ED_CTRL_ID_BRUSH)
2955 CopyAreaToBrush(start_sx, start_sy, sx, sy);
2956 draw_with_brush = TRUE;
2959 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2961 else if (last_sx != sx || last_sy != sy)
2963 draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
2964 draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
2971 case ED_CTRL_ID_TEXT:
2972 if (button_press_event)
2973 DrawLevelText(sx, sy, 0, TEXT_INIT);
2976 case ED_CTRL_ID_FLOOD_FILL:
2977 if (button_press_event && Feld[lx][ly] != new_element)
2979 FloodFill(lx, ly, new_element);
2980 DrawMiniLevel(level_xpos, level_ypos);
2981 CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2985 case ED_CTRL_ID_PICK_ELEMENT:
2986 if (button_press_event)
2987 PickDrawingElement(button, Feld[lx][ly]);
2988 if (button_release_event)
2989 ClickOnGadget(level_editor_gadget[last_drawing_function]);
2997 static void HandleCounterButtons(struct GadgetInfo *gi)
2999 int id = gi->custom_id;
3000 int button = gi->event.button;
3001 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3005 case ED_CTRL_ID_SCORE_DOWN:
3006 case ED_CTRL_ID_SCORE_UP:
3007 *gadget_score_value += (id == ED_CTRL_ID_SCORE_DOWN ? -step : step);
3008 if (*gadget_score_value < 0)
3009 *gadget_score_value = 0;
3010 else if (*gadget_score_value > 255)
3011 *gadget_score_value = 255;
3013 DrawCounterValueField(ED_COUNTER_SCORE, *gadget_score_value);
3016 case ED_CTRL_ID_ELEMCONT_DOWN:
3017 case ED_CTRL_ID_ELEMCONT_UP:
3018 *gadget_areas_value += (id == ED_CTRL_ID_ELEMCONT_DOWN ? -step : step);
3019 if (*gadget_areas_value < 1)
3020 *gadget_areas_value = 1;
3021 else if (*gadget_areas_value > MAX_ELEMCONT)
3022 *gadget_areas_value = MAX_ELEMCONT;
3024 DrawCounterValueField(ED_COUNTER_ELEMCONT, *gadget_areas_value);
3025 DrawElementContentAreas();
3033 static void HandleControlButtons(struct GadgetInfo *gi)
3035 int id = gi->custom_id;
3036 int button = gi->event.button;
3037 int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
3039 int player_present = FALSE;
3040 int level_changed = FALSE;
3043 new_element = (button == 1 ? new_element1 :
3044 button == 2 ? new_element2 :
3045 button == 3 ? new_element3 : 0);
3047 if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT)
3048 DrawLevelText(0, 0, 0, TEXT_END);
3050 if (id < ED_NUM_CTRL1_BUTTONS && id != ED_CTRL_ID_PROPERTIES &&
3051 edit_mode != ED_MODE_DRAWING)
3053 DrawDrawingWindow();
3054 edit_mode = ED_MODE_DRAWING;
3059 case ED_CTRL_ID_SCROLL_LEFT:
3060 if (level_xpos >= 0)
3062 int gadget_id = ED_CTRL_ID_SCROLL_HORIZONTAL;
3063 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3064 struct GadgetScrollbar *gs = &gi->scrollbar;
3066 if (lev_fieldx < ED_FIELDX - 2)
3070 if (level_xpos < -1)
3073 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_RIGHT);
3075 DrawMiniLevel(level_xpos, level_ypos);
3077 AdjustScrollbar(gi, gs->items_max, level_xpos + 1);
3081 case ED_CTRL_ID_SCROLL_RIGHT:
3082 if (level_xpos <= lev_fieldx - ED_FIELDX)
3084 int gadget_id = ED_CTRL_ID_SCROLL_HORIZONTAL;
3085 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3086 struct GadgetScrollbar *gs = &gi->scrollbar;
3088 if (lev_fieldx < ED_FIELDX - 2)
3092 if (level_xpos > lev_fieldx - ED_FIELDX + 1)
3093 level_xpos = lev_fieldx - ED_FIELDX + 1;
3095 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_LEFT);
3097 DrawMiniLevel(level_xpos, level_ypos);
3099 AdjustScrollbar(gi, gs->items_max, level_xpos + 1);
3103 case ED_CTRL_ID_SCROLL_UP:
3104 if (level_ypos >= 0)
3106 int gadget_id = ED_CTRL_ID_SCROLL_VERTICAL;
3107 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3108 struct GadgetScrollbar *gs = &gi->scrollbar;
3110 if (lev_fieldy < ED_FIELDY - 2)
3114 if (level_ypos < -1)
3117 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_DOWN);
3119 DrawMiniLevel(level_xpos, level_ypos);
3121 AdjustScrollbar(gi, gs->items_max, level_ypos + 1);
3125 case ED_CTRL_ID_SCROLL_DOWN:
3126 if (level_ypos <= lev_fieldy - ED_FIELDY)
3128 int gadget_id = ED_CTRL_ID_SCROLL_VERTICAL;
3129 struct GadgetInfo *gi = level_editor_gadget[gadget_id];
3130 struct GadgetScrollbar *gs = &gi->scrollbar;
3132 if (lev_fieldy < ED_FIELDY - 2)
3136 if (level_ypos > lev_fieldy - ED_FIELDY + 1)
3137 level_ypos = lev_fieldy - ED_FIELDY + 1;
3139 ScrollMiniLevel(level_xpos, level_ypos, ED_SCROLL_UP);
3141 DrawMiniLevel(level_xpos, level_ypos);
3143 AdjustScrollbar(gi, gs->items_max, level_ypos + 1);
3147 case ED_CTRL_ID_SCROLL_HORIZONTAL:
3148 level_xpos = gi->event.item_position - 1;
3149 DrawMiniLevel(level_xpos, level_ypos);
3152 case ED_CTRL_ID_SCROLL_VERTICAL:
3153 level_ypos = gi->event.item_position - 1;
3154 DrawMiniLevel(level_xpos, level_ypos);
3157 case ED_CTRL_ID_WRAP_LEFT:
3158 WrapLevel(-step, 0);
3161 case ED_CTRL_ID_WRAP_RIGHT:
3165 case ED_CTRL_ID_WRAP_UP:
3166 WrapLevel(0, -step);
3169 case ED_CTRL_ID_WRAP_DOWN:
3173 case ED_CTRL_ID_SINGLE_ITEMS:
3174 case ED_CTRL_ID_CONNECTED_ITEMS:
3175 case ED_CTRL_ID_LINE:
3176 case ED_CTRL_ID_TEXT:
3177 case ED_CTRL_ID_RECTANGLE:
3178 case ED_CTRL_ID_FILLED_BOX:
3179 case ED_CTRL_ID_FLOOD_FILL:
3180 case ED_CTRL_ID_BRUSH:
3181 case ED_CTRL_ID_PICK_ELEMENT:
3182 last_drawing_function = drawing_function;
3183 drawing_function = id;
3186 case ED_CTRL_ID_RANDOM_PLACEMENT:
3187 RandomPlacement(button);
3190 case ED_CTRL_ID_PROPERTIES:
3191 if (edit_mode != ED_MODE_PROPERTIES)
3193 properties_element = new_element;
3194 DrawPropertiesWindow();
3195 edit_mode = ED_MODE_PROPERTIES;
3199 DrawDrawingWindow();
3200 edit_mode = ED_MODE_DRAWING;
3204 case ED_CTRL_ID_UNDO:
3205 if (undo_buffer_steps == 0)
3207 Request("Undo buffer empty !", REQ_CONFIRM);
3211 undo_buffer_position =
3212 (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
3213 undo_buffer_steps--;
3215 for(x=0; x<lev_fieldx; x++)
3216 for(y=0; y<lev_fieldy; y++)
3217 Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
3218 DrawMiniLevel(level_xpos,level_ypos);
3221 case ED_CTRL_ID_INFO:
3222 if (edit_mode != ED_MODE_INFO)
3224 DrawControlWindow();
3225 edit_mode = ED_MODE_INFO;
3229 DrawDrawingWindow();
3230 edit_mode = ED_MODE_DRAWING;
3234 case ED_CTRL_ID_CLEAR:
3235 for(x=0; x<MAX_LEV_FIELDX; x++)
3236 for(y=0; y<MAX_LEV_FIELDY; y++)
3237 Feld[x][y] = new_element3;
3238 CopyLevelToUndoBuffer(ED_CTRL_ID_CLEAR);
3240 DrawMiniLevel(level_xpos, level_ypos);
3243 case ED_CTRL_ID_SAVE:
3244 if (leveldir[leveldir_nr].readonly)
3246 Request("This level is read only !", REQ_CONFIRM);
3250 for(y=0; y<lev_fieldy; y++)
3251 for(x=0; x<lev_fieldx; x++)
3252 if (Feld[x][y] != Ur[x][y])
3253 level_changed = TRUE;
3255 if (0 && !level_changed)
3257 Request("Level has not changed !", REQ_CONFIRM);
3261 for(y=0; y<lev_fieldy; y++)
3262 for(x=0; x<lev_fieldx; x++)
3263 if (Feld[x][y] == EL_SPIELFIGUR ||
3264 Feld[x][y] == EL_SPIELER1 ||
3265 Feld[x][y] == EL_SP_MURPHY)
3266 player_present = TRUE;
3268 if (!player_present)
3269 Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3272 if (Request("Save this level and kill the old ?", REQ_ASK))
3274 for(x=0; x<lev_fieldx; x++)
3275 for(y=0; y<lev_fieldy; y++)
3276 Ur[x][y] = Feld[x][y];
3277 SaveLevel(level_nr);
3282 case ED_CTRL_ID_TEST:
3283 for(y=0; y<lev_fieldy; y++)
3284 for(x=0; x<lev_fieldx; x++)
3285 if (Feld[x][y] == EL_SPIELFIGUR ||
3286 Feld[x][y] == EL_SPIELER1 ||
3287 Feld[x][y] == EL_SP_MURPHY)
3288 player_present = TRUE;
3290 if (!player_present)
3291 Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
3294 for(x=0; x<lev_fieldx; x++)
3295 for(y=0; y<lev_fieldy; y++)
3296 FieldBackup[x][y] = Ur[x][y];
3298 for(x=0; x<lev_fieldx; x++)
3299 for(y=0; y<lev_fieldy; y++)
3300 Ur[x][y] = Feld[x][y];
3302 UnmapLevelEditorGadgets();
3304 /* draw smaller door */
3305 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3306 DOOR_GFX_PAGEX7, 64,
3309 redraw_mask |= REDRAW_ALL;
3311 CloseDoor(DOOR_CLOSE_ALL);
3313 DrawCompleteVideoDisplay();
3315 if (setup.autorecord)
3316 TapeStartRecording();
3318 level_editor_test_game = TRUE;
3319 game_status = PLAYING;
3325 case ED_CTRL_ID_EXIT:
3326 for(y=0; y<lev_fieldy; y++)
3327 for(x=0; x<lev_fieldx; x++)
3328 if (Feld[x][y] != Ur[x][y])
3329 level_changed = TRUE;
3331 if (!level_changed ||
3332 Request("Level has changed! Exit without saving ?",
3333 REQ_ASK | REQ_STAY_OPEN))
3335 CloseDoor(DOOR_CLOSE_1);
3338 CloseDoor(DOOR_CLOSE_ALL);
3341 /* draw smaller door */
3342 XCopyArea(display, pix[PIX_DOOR], drawto, gc,
3343 DOOR_GFX_PAGEX7, 64,
3346 redraw_mask |= REDRAW_ALL;
3348 game_status = MAINMENU;
3353 CloseDoor(DOOR_CLOSE_1);
3354 XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
3355 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
3356 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3357 OpenDoor(DOOR_OPEN_1);
3363 if (gi->event.type == GD_EVENT_PRESSED)
3364 printf("default: HandleControlButtons: GD_EVENT_PRESSED\n");
3365 else if (gi->event.type == GD_EVENT_RELEASED)
3366 printf("default: HandleControlButtons: GD_EVENT_RELEASED\n");
3367 else if (gi->event.type == GD_EVENT_MOVING)
3368 printf("default: HandleControlButtons: GD_EVENT_MOVING\n");
3370 printf("default: HandleControlButtons: ?\n");
3376 void HandleLevelEditorKeyInput(KeySym key)
3378 if (edit_mode == ED_MODE_DRAWING && drawing_function == ED_CTRL_ID_TEXT)
3380 char letter = getCharFromKeySym(key);
3383 DrawLevelText(0, 0, letter, TEXT_WRITECHAR);
3384 else if (key == XK_Delete || key == XK_BackSpace)
3385 DrawLevelText(0, 0, 0, TEXT_BACKSPACE);
3386 else if (key == XK_Return)
3387 DrawLevelText(0, 0, 0, TEXT_NEWLINE);
3391 static void HandleTextInputGadgets(struct GadgetInfo *gi)
3393 int id = gi->custom_id;
3397 case ED_CTRL_ID_LEVEL_NAME:
3398 strcpy(level.name, gi->text_value);