1 /***********************************************************
2 * Mirror Magic -- McDuffin's Revenge                       *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * editor.c                                                 *
12 ***********************************************************/
13 
14 #include <math.h>
15 
16 #include "libgame/libgame.h"
17 
18 #include "editor.h"
19 #include "screens.h"
20 #include "tools.h"
21 #include "files.h"
22 #include "game.h"
23 
24 /* positions in the level editor */
25 #define ED_WIN_MB_LEFT_XPOS		7
26 #define ED_WIN_MB_LEFT_YPOS		154
27 #define ED_WIN_MB_MIDDLE_XPOS		42
28 #define ED_WIN_MB_MIDDLE_YPOS		ED_WIN_MB_LEFT_YPOS
29 #define ED_WIN_MB_RIGHT_XPOS		77
30 #define ED_WIN_MB_RIGHT_YPOS		ED_WIN_MB_LEFT_YPOS
31 
32 /* other constants for the editor */
33 #define ED_SCROLL_NO			0
34 #define ED_SCROLL_LEFT			1
35 #define ED_SCROLL_RIGHT			2
36 #define ED_SCROLL_UP			4
37 #define ED_SCROLL_DOWN			8
38 
39 /* screens in the level editor */
40 #define ED_MODE_DRAWING			0
41 #define ED_MODE_INFO			1
42 #define ED_MODE_PROPERTIES		2
43 
44 /* how many steps can be cancelled */
45 #define NUM_UNDO_STEPS			(10 + 1)
46 
47 /* values for elements with score */
48 #define MIN_SCORE			0
49 #define MAX_SCORE			255
50 
51 /* values for the control window */
52 #define ED_CTRL_BUTTONS_GFX_YPOS 	178
53 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS 	118
54 
55 #define ED_CTRL1_BUTTONS_HORIZ		4
56 #define ED_CTRL1_BUTTONS_VERT		3
57 #define ED_CTRL1_BUTTON_XSIZE		22
58 #define ED_CTRL1_BUTTON_YSIZE		20
59 #define ED_CTRL1_BUTTONS_XPOS		6
60 #define ED_CTRL1_BUTTONS_YPOS		0
61 #define ED_CTRL2_BUTTONS_HORIZ		3
62 #define ED_CTRL2_BUTTONS_VERT		2
63 #define ED_CTRL2_BUTTON_XSIZE		30
64 #define ED_CTRL2_BUTTON_YSIZE		16
65 #define ED_CTRL2_BUTTONS_XPOS		5
66 #define ED_CTRL2_BUTTONS_YPOS		65
67 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
68 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
69 #define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
70 
71 /* values for the element list */
72 #define ED_ELEMENTLIST_XPOS		5
73 #define ED_ELEMENTLIST_YPOS		26
74 #define ED_ELEMENTLIST_XSIZE		20
75 #define ED_ELEMENTLIST_YSIZE		20
76 #define ED_ELEMENTLIST_BUTTONS_HORIZ	4
77 #define ED_ELEMENTLIST_BUTTONS_VERT	6
78 #define ED_NUM_ELEMENTLIST_BUTTONS	(ED_ELEMENTLIST_BUTTONS_HORIZ * \
79 					 ED_ELEMENTLIST_BUTTONS_VERT)
80 
81 /* values for the drawing element buttons */
82 #define ED_DRAWING_ELEMENT_XPOS		5
83 #define ED_DRAWING_ELEMENT_YPOS		152
84 #define ED_DRAWING_ELEMENT_XSIZE	ED_ELEMENTLIST_XSIZE
85 #define ED_DRAWING_ELEMENT_YSIZE	ED_ELEMENTLIST_YSIZE
86 #define ED_DRAWING_ELEMENT_XDISTANCE	35
87 #define ED_NUM_DRAWING_ELEMENT_BUTTONS	3
88 
89 /* values for the setting windows */
90 #define ED_SETTINGS_XPOS		(MINI_TILEX + 8)
91 #define ED_SETTINGS2_XPOS		MINI_TILEX
92 #define ED_SETTINGS_YPOS		MINI_TILEY
93 #define ED_SETTINGS2_YPOS		(ED_SETTINGS_YPOS + 12 * TILEY - 2)
94 
95 /* values for counter gadgets */
96 #define ED_COUNT_ELEM_SCORE_XPOS	ED_SETTINGS_XPOS
97 #define ED_COUNT_ELEM_SCORE_YPOS	(14 * MINI_TILEY)
98 #define ED_COUNT_ELEM_CONTENT_XPOS	ED_SETTINGS_XPOS
99 #define ED_COUNT_ELEM_CONTENT_YPOS	(19 * MINI_TILEY)
100 
101 #define ED_COUNTER_YSTART		(ED_SETTINGS_YPOS + 2 * TILEY)
102 #define ED_COUNTER_YDISTANCE		(3 * MINI_TILEY)
103 #define ED_COUNTER_YPOS(n)		(ED_COUNTER_YSTART + \
104 					 n * ED_COUNTER_YDISTANCE)
105 #define ED_COUNTER2_YPOS(n)		(ED_COUNTER_YSTART + \
106 					 n * ED_COUNTER_YDISTANCE - 2)
107 /* standard distances */
108 #define ED_BORDER_SIZE			3
109 #define ED_GADGET_DISTANCE		2
110 
111 /* values for element content drawing areas */
112 #define ED_AREA_ELEM_CONTENT_XPOS	( 2 * MINI_TILEX)
113 #define ED_AREA_ELEM_CONTENT_YPOS	(22 * MINI_TILEY)
114 
115 /* values for random placement background drawing area */
116 #define ED_AREA_RANDOM_BACKGROUND_XPOS	(29 * MINI_TILEX)
117 #define ED_AREA_RANDOM_BACKGROUND_YPOS	(31 * MINI_TILEY)
118 
119 /* values for scrolling gadgets for drawing area */
120 #define ED_SCROLLBUTTON_XPOS		24
121 #define ED_SCROLLBUTTON_YPOS		0
122 #define ED_SCROLLBAR_XPOS		24
123 #define ED_SCROLLBAR_YPOS		64
124 
125 #define ED_SCROLLBUTTON_XSIZE		16
126 #define ED_SCROLLBUTTON_YSIZE		16
127 
128 #define ED_SCROLL_UP_XPOS		(SXSIZE - ED_SCROLLBUTTON_XSIZE)
129 #define ED_SCROLL_UP_YPOS		(0)
130 #define ED_SCROLL_DOWN_XPOS		ED_SCROLL_UP_XPOS
131 #define ED_SCROLL_DOWN_YPOS		(SYSIZE - 3 * ED_SCROLLBUTTON_YSIZE)
132 #define ED_SCROLL_LEFT_XPOS		(0)
133 #define ED_SCROLL_LEFT_YPOS		(SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
134 #define ED_SCROLL_RIGHT_XPOS		(SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
135 #define ED_SCROLL_RIGHT_YPOS		ED_SCROLL_LEFT_YPOS
136 #define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + ED_SCROLLBUTTON_XSIZE)
137 #define ED_SCROLL_HORIZONTAL_YPOS	ED_SCROLL_LEFT_YPOS
138 #define ED_SCROLL_HORIZONTAL_XSIZE	(SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
139 #define ED_SCROLL_HORIZONTAL_YSIZE	ED_SCROLLBUTTON_YSIZE
140 #define ED_SCROLL_VERTICAL_XPOS		ED_SCROLL_UP_XPOS
141 #define ED_SCROLL_VERTICAL_YPOS	  (ED_SCROLL_UP_YPOS + ED_SCROLLBUTTON_YSIZE)
142 #define ED_SCROLL_VERTICAL_XSIZE	ED_SCROLLBUTTON_XSIZE
143 #define ED_SCROLL_VERTICAL_YSIZE	(SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
144 
145 /* values for scrolling gadgets for element list */
146 #define ED_SCROLLBUTTON2_XPOS		50
147 #define ED_SCROLLBUTTON2_YPOS		0
148 #define ED_SCROLLBAR2_XPOS		50
149 #define ED_SCROLLBAR2_YPOS		20
150 
151 #define ED_SCROLLBUTTON2_XSIZE		10
152 #define ED_SCROLLBUTTON2_YSIZE		10
153 
154 #define ED_SCROLL2_UP_XPOS		85
155 #define ED_SCROLL2_UP_YPOS		26
156 #define ED_SCROLL2_DOWN_XPOS		ED_SCROLL2_UP_XPOS
157 #define ED_SCROLL2_DOWN_YPOS		(ED_SCROLL2_UP_YPOS + \
158 					 ED_ELEMENTLIST_BUTTONS_VERT * \
159 					 ED_ELEMENTLIST_YSIZE - \
160 					 ED_SCROLLBUTTON2_YSIZE)
161 #define ED_SCROLL2_VERTICAL_XPOS	ED_SCROLL2_UP_XPOS
162 #define ED_SCROLL2_VERTICAL_YPOS	(ED_SCROLL2_UP_YPOS + \
163 					 ED_SCROLLBUTTON2_YSIZE)
164 #define ED_SCROLL2_VERTICAL_XSIZE	ED_SCROLLBUTTON2_XSIZE
165 #define ED_SCROLL2_VERTICAL_YSIZE	(ED_ELEMENTLIST_BUTTONS_VERT * \
166 					 ED_ELEMENTLIST_YSIZE - \
167 					 2 * ED_SCROLLBUTTON2_YSIZE)
168 
169 /* values for checkbutton gadgets */
170 #define ED_CHECKBUTTON_XSIZE		ED_BUTTON_COUNT_XSIZE
171 #define ED_CHECKBUTTON_YSIZE		ED_BUTTON_COUNT_YSIZE
172 #define ED_CHECKBUTTON_UNCHECKED_XPOS	ED_BUTTON_MINUS_XPOS
173 #define ED_CHECKBUTTON_CHECKED_XPOS	ED_BUTTON_PLUS_XPOS
174 #define ED_CHECKBUTTON_YPOS		(ED_BUTTON_MINUS_YPOS + 22)
175 #define ED_RADIOBUTTON_YPOS		(ED_BUTTON_MINUS_YPOS + 44)
176 #define ED_STICKYBUTTON_YPOS		(ED_BUTTON_MINUS_YPOS + 66)
177 
178 /* some positions in the editor control window */
179 #define ED_BUTTON_ELEM_XPOS	6
180 #define ED_BUTTON_ELEM_YPOS	30
181 #define ED_BUTTON_ELEM_XSIZE	22
182 #define ED_BUTTON_ELEM_YSIZE	22
183 
184 /* some values for text input and counter gadgets */
185 #define ED_BUTTON_COUNT_YPOS	60
186 #define ED_BUTTON_COUNT_XSIZE	20
187 #define ED_BUTTON_COUNT_YSIZE	20
188 #define ED_WIN_COUNT_XPOS	(2 + ED_BUTTON_COUNT_XSIZE + 2)
189 #define ED_WIN_COUNT_YPOS	ED_BUTTON_COUNT_YPOS
190 #define ED_WIN_COUNT_XSIZE	52
191 #define ED_WIN_COUNT_YSIZE	ED_BUTTON_COUNT_YSIZE
192 #define ED_WIN_COUNT2_XPOS	27
193 #define ED_WIN_COUNT2_YPOS	3
194 #define ED_WIN_COUNT2_XSIZE	46
195 #define ED_WIN_COUNT2_YSIZE	ED_BUTTON_COUNT_YSIZE
196 
197 #define ED_BUTTON_MINUS_XPOS	2
198 #define ED_BUTTON_MINUS_YPOS	ED_BUTTON_COUNT_YPOS
199 #define ED_BUTTON_MINUS_XSIZE	ED_BUTTON_COUNT_XSIZE
200 #define ED_BUTTON_MINUS_YSIZE	ED_BUTTON_COUNT_YSIZE
201 #define ED_BUTTON_PLUS_XPOS	(ED_WIN_COUNT_XPOS + ED_WIN_COUNT_XSIZE + 2)
202 #define ED_BUTTON_PLUS_YPOS	ED_BUTTON_COUNT_YPOS
203 #define ED_BUTTON_PLUS_XSIZE	ED_BUTTON_COUNT_XSIZE
204 #define ED_BUTTON_PLUS_YSIZE	ED_BUTTON_COUNT_YSIZE
205 
206 /* editor gadget identifiers */
207 
208 /* drawing toolbox buttons */
209 #define GADGET_ID_NONE			-1
210 #define GADGET_ID_SINGLE_ITEMS		0
211 #define GADGET_ID_LINE			1
212 #define GADGET_ID_WRAP_UP		2
213 #define GADGET_ID_ARC			3
214 #define GADGET_ID_FLOOD_FILL		4
215 #define GADGET_ID_WRAP_LEFT		5
216 #define GADGET_ID_GRAB_BRUSH		6
217 #define GADGET_ID_WRAP_RIGHT		7
218 #define GADGET_ID_RECTANGLE		8
219 #define GADGET_ID_FILLED_BOX		9
220 #define GADGET_ID_WRAP_DOWN		10
221 #define GADGET_ID_PICK_ELEMENT		11
222 #define GADGET_ID_UNDO			12
223 #define GADGET_ID_INFO			13
224 #define GADGET_ID_SAVE			14
225 #define GADGET_ID_CLEAR			15
226 #define GADGET_ID_TEST			16
227 #define GADGET_ID_EXIT			17
228 
229 /* counter button identifiers */
230 #define GADGET_ID_LEVEL_COLLECT_DOWN	18
231 #define GADGET_ID_LEVEL_COLLECT_TEXT	19
232 #define GADGET_ID_LEVEL_COLLECT_UP	20
233 #define GADGET_ID_LEVEL_TIMELIMIT_DOWN	21
234 #define GADGET_ID_LEVEL_TIMELIMIT_TEXT	22
235 #define GADGET_ID_LEVEL_TIMELIMIT_UP	23
236 #define GADGET_ID_SELECT_LEVEL_DOWN	24
237 #define GADGET_ID_SELECT_LEVEL_TEXT	25
238 #define GADGET_ID_SELECT_LEVEL_UP	26
239 
240 /* drawing area identifiers */
241 #define GADGET_ID_DRAWING_LEVEL		27
242 
243 /* text input identifiers */
244 #define GADGET_ID_LEVEL_NAME		28
245 #define GADGET_ID_LEVEL_AUTHOR		29
246 
247 /* gadgets for scrolling element list */
248 #define GADGET_ID_SCROLL_LIST_UP	30
249 #define GADGET_ID_SCROLL_LIST_DOWN	31
250 #define GADGET_ID_SCROLL_LIST_VERTICAL	32
251 
252 /* buttons for level settings */
253 #define GADGET_ID_AUTO_COUNT		33
254 #define GADGET_ID_LASER_RED		34
255 #define GADGET_ID_LASER_GREEN		35
256 #define GADGET_ID_LASER_BLUE		36
257 
258 /* gadgets for drawing element buttons */
259 #define GADGET_ID_DRAWING_ELEMENT_LEFT	 37
260 #define GADGET_ID_DRAWING_ELEMENT_MIDDLE 38
261 #define GADGET_ID_DRAWING_ELEMENT_RIGHT	 39
262 
263 /* gadgets for buttons in element list */
264 #define GADGET_ID_ELEMENTLIST_FIRST	40
265 #define GADGET_ID_ELEMENTLIST_LAST	(GADGET_ID_ELEMENTLIST_FIRST +	\
266 					 ED_NUM_ELEMENTLIST_BUTTONS - 1)
267 
268 #define NUM_EDITOR_GADGETS		(GADGET_ID_ELEMENTLIST_LAST + 1)
269 
270 /* radio button numbers */
271 #define RADIO_NR_NONE			0
272 #define RADIO_NR_DRAWING_TOOLBOX	1
273 #define RADIO_NR_RANDOM_ELEMENTS	2
274 
275 /* values for counter gadgets */
276 #define ED_COUNTER_ID_LEVEL_COLLECT	0
277 #define ED_COUNTER_ID_LEVEL_TIMELIMIT	1
278 #define ED_COUNTER_ID_SELECT_LEVEL	2
279 
280 #define ED_NUM_COUNTERBUTTONS		3
281 
282 #define ED_COUNTER_ID_LEVEL_FIRST	ED_COUNTER_ID_LEVEL_COLLECT
283 #define ED_COUNTER_ID_LEVEL_LAST	ED_COUNTER_ID_SELECT_LEVEL
284 
285 /* values for scrollbutton gadgets */
286 #define ED_SCROLLBUTTON_ID_LIST_UP	0
287 #define ED_SCROLLBUTTON_ID_LIST_DOWN	1
288 
289 #define ED_NUM_SCROLLBUTTONS		2
290 
291 /* values for additional counter graphics */
292 #define ED_DUMMYBUTTON_ID_LEVEL_LEFT	0
293 #define ED_DUMMYBUTTON_ID_LEVEL_RIGHT	1
294 
295 #define ED_NUM_DUMMYBUTTONS		2
296 
297 #define ED_SCROLLBUTTON_ID_AREA_FIRST	ED_SCROLLBUTTON_ID_AREA_UP
298 #define ED_SCROLLBUTTON_ID_AREA_LAST	ED_SCROLLBUTTON_ID_AREA_RIGHT
299 
300 /* values for scrollbar gadgets */
301 #define ED_SCROLLBAR_ID_LIST_VERTICAL	0
302 
303 #define ED_NUM_SCROLLBARS		1
304 
305 #define ED_SCROLLBAR_ID_AREA_FIRST	ED_SCROLLBAR_ID_AREA_HORIZONTAL
306 #define ED_SCROLLBAR_ID_AREA_LAST	ED_SCROLLBAR_ID_AREA_VERTICAL
307 
308 /* values for text input gadgets */
309 #define ED_TEXTINPUT_ID_LEVEL_NAME	0
310 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR	1
311 
312 #define ED_NUM_TEXTINPUT		2
313 
314 #define ED_TEXTINPUT_ID_LEVEL_FIRST	ED_TEXTINPUT_ID_LEVEL_NAME
315 #define ED_TEXTINPUT_ID_LEVEL_LAST	ED_TEXTINPUT_ID_LEVEL_AUTHOR
316 
317 /* values for checkbutton gadgets */
318 #define ED_CHECKBUTTON_ID_AUTO_COUNT		0
319 #define ED_CHECKBUTTON_ID_LASER_RED		1
320 #define ED_CHECKBUTTON_ID_LASER_GREEN		2
321 #define ED_CHECKBUTTON_ID_LASER_BLUE		3
322 
323 #define ED_NUM_CHECKBUTTONS			4
324 
325 #define ED_CHECKBUTTON_ID_LEVEL_FIRST	ED_CHECKBUTTON_ID_AUTO_COUNT
326 #define ED_CHECKBUTTON_ID_LEVEL_LAST	ED_CHECKBUTTON_ID_LASER_BLUE
327 
328 /* values for CopyLevelToUndoBuffer() */
329 #define UNDO_IMMEDIATE			0
330 #define UNDO_ACCUMULATE			1
331 
332 /* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
333 #define INFOTEXT_XPOS			SX
334 #define INFOTEXT_YPOS			(SY + SYSIZE - MINI_TILEX + 2)
335 #define INFOTEXT_XSIZE			SXSIZE
336 #define INFOTEXT_YSIZE			MINI_TILEX
337 #define MAX_INFOTEXT_LEN		(SXSIZE / FONT2_XSIZE)
338 
339 static struct
340 {
341   char shortcut;
342   char *text;
343 } control_info[ED_NUM_CTRL_BUTTONS] =
344 {
345   { 's', "draw single items" },
346   { 'l', "draw lines" },
347   { '\0', "wrap (rotate) level up" },
348   { 'a', "draw arcs" },
349 
350   { 'f', "flood fill" },
351   { '\0', "wrap (rotate) level left" },
352   { 'b', "grab brush" },
353   { '\0', "wrap (rotate) level right" },
354 
355   { 'r', "draw outline rectangles" },
356   { 'R', "draw filled rectangles" },
357   { '\0', "wrap (rotate) level down" },
358   { ',', "pick drawing element" },
359 
360   { 'U', "undo last operation" },
361   { 'I', "level properties" },
362   { 'S', "save level" },
363 
364   { 'C', "clear level" },
365   { 'T', "test level" },
366   { 'E', "exit level editor" }
367 };
368 
369 static struct
370 {
371   int x, y;
372   int min_value, max_value;
373   int gadget_id_down, gadget_id_up;
374   int gadget_id_text;
375   int *value;
376   char *infotext_above, *infotext_right;
377 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
378 {
379   {
380     ED_SETTINGS_XPOS,			ED_COUNTER_YPOS(3),
381     0,					999,
382     GADGET_ID_LEVEL_COLLECT_DOWN,	GADGET_ID_LEVEL_COLLECT_UP,
383     GADGET_ID_LEVEL_COLLECT_TEXT,
384     &level.kettles_needed,
385     "number of kettles to collect",	NULL
386   },
387   {
388     ED_SETTINGS_XPOS,			ED_COUNTER_YPOS(4),
389     0,					MAX_LASER_ENERGY,
390     GADGET_ID_LEVEL_TIMELIMIT_DOWN,	GADGET_ID_LEVEL_TIMELIMIT_UP,
391     GADGET_ID_LEVEL_TIMELIMIT_TEXT,
392     &level.time,
393     "time available to solve level",	"(0 => no time limit)"
394   },
395   {
396     DX + 5 - SX,			DY + 3 - SY,
397     1,					100,
398     GADGET_ID_SELECT_LEVEL_DOWN,	GADGET_ID_SELECT_LEVEL_UP,
399     GADGET_ID_SELECT_LEVEL_TEXT,
400     &level_nr,
401     NULL,				NULL
402   }
403 };
404 
405 static struct
406 {
407   int x, y;
408   int gadget_id;
409   int size;
410   char *value;
411   char *infotext;
412 } textinput_info[ED_NUM_TEXTINPUT] =
413 {
414   {
415     ED_SETTINGS_XPOS,			ED_COUNTER_YPOS(0),
416     GADGET_ID_LEVEL_NAME,
417     MAX_LEVEL_NAME_LEN,
418     level.name,
419     "Title"
420   },
421   {
422     ED_SETTINGS_XPOS,			ED_COUNTER_YPOS(1),
423     GADGET_ID_LEVEL_AUTHOR,
424     MAX_LEVEL_AUTHOR_LEN,
425     level.author,
426     "Author"
427   }
428 };
429 
430 static struct
431 {
432   int xpos, ypos;
433   int x, y;
434   int gadget_id;
435   char *infotext;
436 } scrollbutton_info[ED_NUM_SCROLLBUTTONS] =
437 {
438   {
439     ED_SCROLLBUTTON2_XPOS,  ED_SCROLLBUTTON2_YPOS + 0 * ED_SCROLLBUTTON2_YSIZE,
440     ED_SCROLL2_UP_XPOS,     ED_SCROLL2_UP_YPOS,
441     GADGET_ID_SCROLL_LIST_UP,
442     "scroll element list up ('Page Up')"
443   },
444   {
445     ED_SCROLLBUTTON2_XPOS,  ED_SCROLLBUTTON2_YPOS + 1 * ED_SCROLLBUTTON2_YSIZE,
446     ED_SCROLL2_DOWN_XPOS,    ED_SCROLL2_DOWN_YPOS,
447     GADGET_ID_SCROLL_LIST_DOWN,
448     "scroll element list down ('Page Down')"
449   }
450 }, dummybutton_info[ED_NUM_DUMMYBUTTONS] =
451 {
452   {
453     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 2 * ED_SCROLLBUTTON_YSIZE,
454     ED_SCROLL_LEFT_XPOS,    ED_SCROLL_LEFT_YPOS,
455     GADGET_ID_NONE,
456     "[dummy level down]"
457   },
458   {
459     ED_SCROLLBUTTON_XPOS,   ED_SCROLLBUTTON_YPOS + 3 * ED_SCROLLBUTTON_YSIZE,
460     ED_SCROLL_RIGHT_XPOS,   ED_SCROLL_RIGHT_YPOS,
461     GADGET_ID_NONE,
462     "[dummy level up]"
463   },
464 }
465 ;
466 
467 static struct
468 {
469   int xpos, ypos;
470   int x, y;
471   int width, height;
472   int type;
473   int gadget_id;
474   char *infotext;
475 } scrollbar_info[ED_NUM_SCROLLBARS] =
476 {
477   {
478     ED_SCROLLBAR2_XPOS,			ED_SCROLLBAR2_YPOS,
479     DX + ED_SCROLL2_VERTICAL_XPOS,	DY + ED_SCROLL2_VERTICAL_YPOS,
480     ED_SCROLL2_VERTICAL_XSIZE,		ED_SCROLL2_VERTICAL_YSIZE,
481     GD_TYPE_SCROLLBAR_VERTICAL,
482     GADGET_ID_SCROLL_LIST_VERTICAL,
483     "scroll element list vertically"
484   }
485 };
486 
487 static struct
488 {
489   int x, y;
490   int gadget_id;
491   boolean *value;
492   char *text, *infotext;
493 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
494 {
495   {
496     ED_SETTINGS_XPOS + 160,		ED_COUNTER_YPOS(3),
497     GADGET_ID_AUTO_COUNT,
498     &level.auto_count_kettles,
499     "auto count kettles",		"set counter to number of kettles"
500   },
501   {
502     ED_SETTINGS_XPOS,			ED_COUNTER_YPOS(5),
503     GADGET_ID_LASER_RED,
504     &level.laser_red,
505     "red",				"use red color component in laser"
506   },
507   {
508     ED_SETTINGS_XPOS + 120,		ED_COUNTER_YPOS(5),
509     GADGET_ID_LASER_GREEN,
510     &level.laser_green,
511     "green",				"use green color component in laser"
512   },
513   {
514     ED_SETTINGS_XPOS + 240,		ED_COUNTER_YPOS(5),
515     GADGET_ID_LASER_BLUE,
516     &level.laser_blue,
517     "blue",				"use blue color component in laser"
518   }
519 };
520 
521 /* maximal size of level editor drawing area */
522 #define MAX_ED_FIELDX		(2 * SCR_FIELDX)
523 #define MAX_ED_FIELDY		(2 * SCR_FIELDY)
524 
525 /* actual size of level editor drawing area */
526 static int ed_fieldx = MAX_ED_FIELDX, ed_fieldy = MAX_ED_FIELDY;
527 
528 /* actual position of level editor drawing area in level playfield */
529 static int level_xpos = 0, level_ypos = 0;
530 
531 #define IN_ED_FIELD(x,y)  ((x)>=0 && (x)<ed_fieldx && (y)>=0 &&(y)<ed_fieldy)
532 
533 /* drawing elements on the three mouse buttons */
534 static int new_drawing_element[4] =
535 {
536   0,			/* dummy for convenient access by 1, 2 and 3 */
537   EL_MIRROR_START,
538   EL_EMPTY,
539   EL_WALL_WOOD
540 };
541 
542 #define BUTTON_ELEMENT(button) ((button) >= 1 && (button) <= 3 ?	\
543 				new_drawing_element[button] : EL_EMPTY)
544 #define BUTTON_STEPSIZE(button) ((button) == 1 ? 1 : (button) == 2 ? 5 : 10)
545 
546 /* forward declaration for internal use */
547 static void ModifyEditorCounter(int, int);
548 static void ModifyEditorCounterLimits(int, int, int);
549 static void DrawDrawingWindow();
550 static void DrawLevelInfoWindow();
551 static void CopyLevelToUndoBuffer(int);
552 static void HandleDrawingAreas(struct GadgetInfo *);
553 static void HandleCounterButtons(struct GadgetInfo *);
554 static void HandleTextInputGadgets(struct GadgetInfo *);
555 static void HandleCheckbuttons(struct GadgetInfo *);
556 static void HandleControlButtons(struct GadgetInfo *);
557 static void HandleDrawingAreaInfo(struct GadgetInfo *);
558 
559 static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
560 
561 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
562 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
563 static boolean draw_with_brush = FALSE;
564 
565 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
566 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
567 static int undo_buffer_position = 0;
568 static int undo_buffer_steps = 0;
569 
570 static int edit_mode;
571 
572 static int counter_xsize = DXSIZE + FONT2_XSIZE - 2 * ED_GADGET_DISTANCE;
573 
574 int element_shift = 0;
575 
576 int editor_element[] =
577 {
578   EL_CHAR('M'),
579   EL_CHAR('I'),
580   EL_CHAR('N'),
581   EL_CHAR('D'),
582 
583   EL_CHAR('B'),
584   EL_CHAR('E'),
585   EL_CHAR('N'),
586   EL_CHAR('-'),
587 
588   EL_CHAR('D'),
589   EL_CHAR('E'),
590   EL_CHAR('R'),
591   EL_EMPTY,
592 
593   EL_MCDUFFIN_RIGHT,
594   EL_MCDUFFIN_UP,
595   EL_MCDUFFIN_LEFT,
596   EL_MCDUFFIN_DOWN,
597 
598   EL_MIRROR_START,
599   EL_MIRROR_FIXED_START,
600   EL_POLAR_START,
601   EL_POLAR_CROSS_START,
602 
603   EL_BEAMER_RED_START,
604   EL_BEAMER_YELLOW_START,
605   EL_BEAMER_GREEN_START,
606   EL_BEAMER_BLUE_START,
607 
608   EL_PRISM,
609   EL_FUSE_ON,
610   EL_PACMAN_RIGHT,
611   EL_EXIT_CLOSED,
612 
613   EL_KETTLE,
614   EL_BOMB,
615   EL_KEY,
616   EL_FUEL_FULL,
617 
618   EL_LIGHTBULB_OFF,
619   EL_LIGHTBULB_ON,
620   EL_BALL_GRAY,
621   EL_LIGHTBALL,
622 
623   EL_WALL_STEEL,
624   EL_WALL_WOOD,
625   EL_WALL_ICE,
626   EL_WALL_AMOEBA,
627 
628   EL_GATE_STONE,
629   EL_GATE_WOOD,
630   EL_BLOCK_STONE,
631   EL_BLOCK_WOOD,
632 
633   EL_GRID_STEEL_00,
634   EL_GRID_STEEL_01,
635   EL_GRID_STEEL_02,
636   EL_GRID_STEEL_03,
637 
638   EL_GRID_WOOD_00,
639   EL_GRID_WOOD_01,
640   EL_GRID_WOOD_02,
641   EL_GRID_WOOD_03,
642 
643   EL_CHAR('D'),
644   EL_CHAR('E'),
645   EL_CHAR('-'),
646   EL_EMPTY,
647 
648   EL_CHAR('F'),
649   EL_CHAR('L'),
650   EL_CHAR('E'),
651   EL_CHAR('K'),
652 
653   EL_CHAR('T'),
654   EL_CHAR('O'),
655   EL_CHAR('R'),
656   EL_EMPTY,
657 
658   EL_LASER_UP,
659   EL_RECEIVER_UP,
660   EL_DF_MIRROR_START,
661   EL_DF_MIRROR_AUTO_START,
662 
663   EL_FIBRE_OPTIC_00,
664   EL_FIBRE_OPTIC_02,
665   EL_FIBRE_OPTIC_04,
666   EL_FIBRE_OPTIC_06,
667 
668   EL_GRID_STEEL_FIXED_START,
669   EL_GRID_STEEL_AUTO_START,
670   EL_GRID_WOOD_FIXED_START,
671   EL_GRID_WOOD_AUTO_START,
672 
673   EL_DF_WALL_STEEL,
674   EL_DF_WALL_WOOD,
675   EL_REFRACTOR,
676   EL_EMPTY,
677 
678   EL_CELL,
679   EL_MINE,
680   EL_EMPTY,
681   EL_EMPTY,
682 
683   EL_EMPTY,
684   EL_EMPTY,
685   EL_EMPTY,
686   EL_EMPTY,
687 
688   EL_CHAR(' '),
689   EL_CHAR('!'),
690   EL_CHAR('"'),
691   EL_CHAR('#'),
692 
693   EL_CHAR('$'),
694   EL_CHAR('%'),
695   EL_CHAR('&'),
696   EL_CHAR('\''),
697 
698   EL_CHAR('('),
699   EL_CHAR(')'),
700   EL_CHAR('*'),
701   EL_CHAR('+'),
702 
703   EL_CHAR(','),
704   EL_CHAR('-'),
705   EL_CHAR('.'),
706   EL_CHAR('/'),
707 
708   EL_CHAR('0'),
709   EL_CHAR('1'),
710   EL_CHAR('2'),
711   EL_CHAR('3'),
712 
713   EL_CHAR('4'),
714   EL_CHAR('5'),
715   EL_CHAR('6'),
716   EL_CHAR('7'),
717 
718   EL_CHAR('8'),
719   EL_CHAR('9'),
720   EL_CHAR(':'),
721   EL_CHAR(';'),
722 
723   EL_CHAR('<'),
724   EL_CHAR('='),
725   EL_CHAR('>'),
726   EL_CHAR('?'),
727 
728   EL_CHAR('@'),
729   EL_CHAR('A'),
730   EL_CHAR('B'),
731   EL_CHAR('C'),
732 
733   EL_CHAR('D'),
734   EL_CHAR('E'),
735   EL_CHAR('F'),
736   EL_CHAR('G'),
737 
738   EL_CHAR('H'),
739   EL_CHAR('I'),
740   EL_CHAR('J'),
741   EL_CHAR('K'),
742 
743   EL_CHAR('L'),
744   EL_CHAR('M'),
745   EL_CHAR('N'),
746   EL_CHAR('O'),
747 
748   EL_CHAR('P'),
749   EL_CHAR('Q'),
750   EL_CHAR('R'),
751   EL_CHAR('S'),
752 
753   EL_CHAR('T'),
754   EL_CHAR('U'),
755   EL_CHAR('V'),
756   EL_CHAR('W'),
757 
758   EL_CHAR('X'),
759   EL_CHAR('Y'),
760   EL_CHAR('Z'),
761   EL_CHAR('�'),
762 
763   EL_CHAR('�'),
764   EL_CHAR('�'),
765   EL_CHAR('^'),
766   EL_CHAR(' ')
767 };
768 int elements_in_list = sizeof(editor_element)/sizeof(int);
769 
getElementInfoText(int element)770 static char *getElementInfoText(int element)
771 {
772   char *info_text = "unknown";
773 
774   if (element < num_element_info)
775     info_text = element_info[element];
776   else
777     Error(ERR_WARN, "no element description for element %d", element);
778 
779   return info_text;
780 }
781 
CreateControlButtons()782 static void CreateControlButtons()
783 {
784   Bitmap *gd_bitmap = pix[PIX_DOOR];
785   struct GadgetInfo *gi;
786   unsigned long event_mask;
787   int i;
788 
789   /* create toolbox buttons */
790   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
791   {
792     int id = i;
793     int width, height;
794     int gd_xoffset, gd_yoffset;
795     int gd_x1, gd_x2, gd_y1, gd_y2;
796     int button_type;
797     int radio_button_nr;
798     boolean checked;
799 
800     if (id == GADGET_ID_SINGLE_ITEMS ||
801 	id == GADGET_ID_LINE ||
802 	id == GADGET_ID_ARC ||
803 	id == GADGET_ID_RECTANGLE ||
804 	id == GADGET_ID_FILLED_BOX ||
805 	id == GADGET_ID_FLOOD_FILL ||
806 	id == GADGET_ID_GRAB_BRUSH ||
807 	id == GADGET_ID_PICK_ELEMENT)
808     {
809       button_type = GD_TYPE_RADIO_BUTTON;
810       radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
811       checked = (id == drawing_function ? TRUE : FALSE);
812       event_mask = GD_EVENT_PRESSED;
813     }
814     else
815     {
816       button_type = GD_TYPE_NORMAL_BUTTON;
817       radio_button_nr = RADIO_NR_NONE;
818       checked = FALSE;
819 
820       if (id == GADGET_ID_WRAP_LEFT ||
821 	  id == GADGET_ID_WRAP_RIGHT ||
822 	  id == GADGET_ID_WRAP_UP ||
823 	  id == GADGET_ID_WRAP_DOWN)
824 	event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
825       else
826 	event_mask = GD_EVENT_RELEASED;
827     }
828 
829     if (id < ED_NUM_CTRL1_BUTTONS)
830     {
831       int x = i % ED_CTRL1_BUTTONS_HORIZ;
832       int y = i / ED_CTRL1_BUTTONS_HORIZ;
833 
834       gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
835       gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
836       width = ED_CTRL1_BUTTON_XSIZE;
837       height = ED_CTRL1_BUTTON_YSIZE;
838     }
839     else
840     {
841       int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
842       int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
843 
844       gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
845       gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
846       width = ED_CTRL2_BUTTON_XSIZE;
847       height = ED_CTRL2_BUTTON_YSIZE;
848     }
849 
850     gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
851     gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
852     gd_y1  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_GFX_YPOS + gd_yoffset;
853     gd_y2  = DOOR_GFX_PAGEY1 + ED_CTRL_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
854 
855     gi = CreateGadget(GDI_CUSTOM_ID, id,
856 		      GDI_CUSTOM_TYPE_ID, i,
857 		      GDI_INFO_TEXT, control_info[i].text,
858 		      GDI_X, EX + gd_xoffset,
859 		      GDI_Y, EY + gd_yoffset,
860 		      GDI_WIDTH, width,
861 		      GDI_HEIGHT, height,
862 		      GDI_TYPE, button_type,
863 		      GDI_STATE, GD_BUTTON_UNPRESSED,
864 		      GDI_RADIO_NR, radio_button_nr,
865 		      GDI_CHECKED, checked,
866 		      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
867 		      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
868 		      GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
869 		      GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
870 		      GDI_EVENT_MASK, event_mask,
871 		      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
872 		      GDI_CALLBACK_ACTION, HandleControlButtons,
873 		      GDI_END);
874 
875     if (gi == NULL)
876       Error(ERR_EXIT, "cannot create gadget");
877 
878     level_editor_gadget[id] = gi;
879   }
880 
881   /* create buttons for scrolling of drawing area and element list */
882   for (i=0; i<ED_NUM_SCROLLBUTTONS; i++)
883   {
884     int id = scrollbutton_info[i].gadget_id;
885     int x, y, width, height;
886     int gd_x1, gd_x2, gd_y1, gd_y2;
887 
888     x = scrollbutton_info[i].x;
889     y = scrollbutton_info[i].y;
890 
891     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
892 
893     x += DX;
894     y += DY;
895     width = ED_SCROLLBUTTON2_XSIZE;
896     height = ED_SCROLLBUTTON2_YSIZE;
897     gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].xpos;
898     gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
899     gd_x2 = gd_x1 - ED_SCROLLBUTTON2_XSIZE;
900     gd_y2 = gd_y1;
901 
902     gi = CreateGadget(GDI_CUSTOM_ID, id,
903 		      GDI_CUSTOM_TYPE_ID, i,
904 		      GDI_INFO_TEXT, scrollbutton_info[i].infotext,
905 		      GDI_X, x,
906 		      GDI_Y, y,
907 		      GDI_WIDTH, width,
908 		      GDI_HEIGHT, height,
909 		      GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
910 		      GDI_STATE, GD_BUTTON_UNPRESSED,
911 		      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
912 		      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
913 		      GDI_EVENT_MASK, event_mask,
914 		      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
915 		      GDI_CALLBACK_ACTION, HandleControlButtons,
916 		      GDI_END);
917 
918     if (gi == NULL)
919       Error(ERR_EXIT, "cannot create gadget");
920 
921     level_editor_gadget[id] = gi;
922   }
923 
924   /* create buttons for element list */
925   for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
926   {
927     Bitmap *deco_bitmap;
928     int deco_x, deco_y, deco_xpos, deco_ypos;
929     int gd_xoffset, gd_yoffset;
930     int gd_x1, gd_x2, gd_y;
931     int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
932     int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
933     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
934     int element = editor_element[i];
935 
936     event_mask = GD_EVENT_RELEASED;
937 
938     gd_xoffset = ED_ELEMENTLIST_XPOS + x * ED_ELEMENTLIST_XSIZE;
939     gd_yoffset = ED_ELEMENTLIST_YPOS + y * ED_ELEMENTLIST_YSIZE;
940 
941     gd_x1 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS + ED_ELEMENTLIST_XSIZE;
942     gd_x2 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
943     gd_y  = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
944 
945     getMiniGraphicSource(el2gfx(element), &deco_bitmap, &deco_x, &deco_y);
946     deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2;
947     deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
948 
949     gi = CreateGadget(GDI_CUSTOM_ID, id,
950 		      GDI_CUSTOM_TYPE_ID, i,
951 		      GDI_INFO_TEXT, getElementInfoText(element),
952 		      GDI_X, DX + gd_xoffset,
953 		      GDI_Y, DY + gd_yoffset,
954 		      GDI_WIDTH, ED_ELEMENTLIST_XSIZE,
955 		      GDI_HEIGHT, ED_ELEMENTLIST_YSIZE,
956 		      GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
957 		      GDI_STATE, GD_BUTTON_UNPRESSED,
958 		      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
959 		      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
960 		      GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
961 		      GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
962 		      GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
963 		      GDI_DECORATION_SHIFTING, 1, 1,
964 		      GDI_EVENT_MASK, event_mask,
965 		      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
966 		      GDI_CALLBACK_ACTION, HandleControlButtons,
967 		      GDI_END);
968 
969     if (gi == NULL)
970       Error(ERR_EXIT, "cannot create gadget");
971 
972     level_editor_gadget[id] = gi;
973   }
974 
975   /* create buttons for drawing element buttons */
976   for (i=0; i<ED_NUM_DRAWING_ELEMENT_BUTTONS; i++)
977   {
978     Bitmap *deco_bitmap;
979     int deco_x, deco_y, deco_xpos, deco_ypos;
980     int gd_xoffset, gd_yoffset;
981     int gd_x1, gd_x2, gd_y;
982     int id = GADGET_ID_DRAWING_ELEMENT_LEFT + i;
983     int element = BUTTON_ELEMENT(i + 1);
984 
985     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
986 
987     gd_xoffset = ED_DRAWING_ELEMENT_XPOS + i * ED_DRAWING_ELEMENT_XDISTANCE;
988     gd_yoffset = ED_DRAWING_ELEMENT_YPOS;
989 
990     gd_x1 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS + ED_ELEMENTLIST_XSIZE;
991     gd_x2 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
992     gd_y  = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
993 
994     getMiniGraphicSource(el2gfx(element), &deco_bitmap, &deco_x, &deco_y);
995     deco_xpos = (ED_DRAWING_ELEMENT_XSIZE - MINI_TILEX) / 2;
996     deco_ypos = (ED_DRAWING_ELEMENT_YSIZE - MINI_TILEY) / 2;
997 
998     gi = CreateGadget(GDI_CUSTOM_ID, id,
999 		      GDI_CUSTOM_TYPE_ID, i,
1000 		      GDI_INFO_TEXT, getElementInfoText(element),
1001 		      GDI_X, DX + gd_xoffset,
1002 		      GDI_Y, DY + gd_yoffset,
1003 		      GDI_WIDTH, ED_ELEMENTLIST_XSIZE,
1004 		      GDI_HEIGHT, ED_ELEMENTLIST_YSIZE,
1005 		      GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1006 		      GDI_STATE, GD_BUTTON_UNPRESSED,
1007 		      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
1008 		      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
1009 		      GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
1010 		      GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
1011 		      GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
1012 		      GDI_DECORATION_SHIFTING, 1, 1,
1013 		      GDI_EVENT_MASK, event_mask,
1014 		      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
1015 		      GDI_CALLBACK_ACTION, HandleControlButtons,
1016 		      GDI_END);
1017 
1018     if (gi == NULL)
1019       Error(ERR_EXIT, "cannot create gadget");
1020 
1021     level_editor_gadget[id] = gi;
1022   }
1023 }
1024 
CreateCounterButtons()1025 static void CreateCounterButtons()
1026 {
1027   int i;
1028 
1029   for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
1030   {
1031     int j;
1032     int xpos = SX + counterbutton_info[i].x;	/* xpos of down count button */
1033     int ypos = SY + counterbutton_info[i].y;
1034 
1035     for (j=0; j<2; j++)
1036     {
1037       Bitmap *gd_bitmap = pix[PIX_DOOR];
1038       struct GadgetInfo *gi;
1039       int id = (j == 0 ?
1040 		counterbutton_info[i].gadget_id_down :
1041 		counterbutton_info[i].gadget_id_up);
1042       int gd_xoffset;
1043       int gd_x, gd_x1, gd_x2, gd_y;
1044       int x_size, y_size;
1045       unsigned long event_mask;
1046       char infotext[MAX_INFOTEXT_LEN + 1];
1047 
1048       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
1049 
1050       if (i == ED_COUNTER_ID_SELECT_LEVEL)
1051       {
1052 	int sid = (j == 0 ?
1053 		   ED_DUMMYBUTTON_ID_LEVEL_LEFT :
1054 		   ED_DUMMYBUTTON_ID_LEVEL_RIGHT);
1055 
1056 	event_mask |= GD_EVENT_RELEASED;
1057 
1058 	if (j == 1)
1059 	  xpos += 2 * ED_GADGET_DISTANCE;
1060 	ypos += ED_GADGET_DISTANCE;
1061 
1062 	gd_x1 = DOOR_GFX_PAGEX8 + dummybutton_info[sid].xpos;
1063 	gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
1064 	gd_y  = DOOR_GFX_PAGEY1 + dummybutton_info[sid].ypos;
1065 	x_size = ED_SCROLLBUTTON_XSIZE;
1066 	y_size = ED_SCROLLBUTTON_YSIZE;
1067       }
1068       else
1069       {
1070 	gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
1071 	gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
1072 	gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
1073 	gd_y  = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
1074 	x_size = ED_BUTTON_COUNT_XSIZE;
1075 	y_size = ED_BUTTON_COUNT_YSIZE;
1076       }
1077 
1078       sprintf(infotext, "%s counter value by 1, 5 or 10",
1079 	      (j == 0 ? "decrease" : "increase"));
1080 
1081       gi = CreateGadget(GDI_CUSTOM_ID, id,
1082 			GDI_CUSTOM_TYPE_ID, i,
1083 			GDI_INFO_TEXT, infotext,
1084 			GDI_X, xpos,
1085 			GDI_Y, ypos,
1086 			GDI_WIDTH, x_size,
1087 			GDI_HEIGHT, y_size,
1088 			GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1089 			GDI_STATE, GD_BUTTON_UNPRESSED,
1090 			GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
1091 			GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
1092 			GDI_EVENT_MASK, event_mask,
1093 			GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
1094 			GDI_CALLBACK_ACTION, HandleCounterButtons,
1095 			GDI_END);
1096 
1097       if (gi == NULL)
1098 	Error(ERR_EXIT, "cannot create gadget");
1099 
1100       level_editor_gadget[id] = gi;
1101       xpos += gi->width + ED_GADGET_DISTANCE;	/* xpos of text count button */
1102 
1103       if (j == 0)
1104       {
1105 	int font_type = FC_YELLOW;
1106 	int gd_width = ED_WIN_COUNT_XSIZE;
1107 
1108 	id = counterbutton_info[i].gadget_id_text;
1109 	event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
1110 
1111 	if (i == ED_COUNTER_ID_SELECT_LEVEL)
1112 	{
1113 	  font_type = FC_SPECIAL3;
1114 
1115 	  xpos += 2 * ED_GADGET_DISTANCE;
1116 	  ypos -= ED_GADGET_DISTANCE;
1117 
1118 	  gd_x = DOOR_GFX_PAGEX6 + ED_WIN_COUNT2_XPOS;
1119 	  gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT2_YPOS;
1120 	  gd_width = ED_WIN_COUNT2_XSIZE;
1121 	}
1122 	else
1123 	{
1124 	  gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
1125 	  gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
1126 	}
1127 
1128 	gi = CreateGadget(GDI_CUSTOM_ID, id,
1129 			  GDI_CUSTOM_TYPE_ID, i,
1130 			  GDI_INFO_TEXT, "enter counter value",
1131 			  GDI_X, xpos,
1132 			  GDI_Y, ypos,
1133 			  GDI_TYPE, GD_TYPE_TEXTINPUT_NUMERIC,
1134 			  GDI_NUMBER_VALUE, 0,
1135 			  GDI_NUMBER_MIN, counterbutton_info[i].min_value,
1136 			  GDI_NUMBER_MAX, counterbutton_info[i].max_value,
1137 			  GDI_TEXT_SIZE, 3,
1138 			  GDI_TEXT_FONT, font_type,
1139 			  GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
1140 			  GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
1141 			  GDI_BORDER_SIZE, ED_BORDER_SIZE,
1142 			  GDI_TEXTINPUT_DESIGN_WIDTH, gd_width,
1143 			  GDI_EVENT_MASK, event_mask,
1144 			  GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
1145 			  GDI_CALLBACK_ACTION, HandleCounterButtons,
1146 			  GDI_END);
1147 
1148 	if (gi == NULL)
1149 	  Error(ERR_EXIT, "cannot create gadget");
1150 
1151 	level_editor_gadget[id] = gi;
1152 	xpos += gi->width + ED_GADGET_DISTANCE;	/* xpos of up count button */
1153       }
1154     }
1155   }
1156 }
1157 
CreateDrawingArea()1158 static void CreateDrawingArea()
1159 {
1160   struct GadgetInfo *gi;
1161   unsigned long event_mask;
1162   int id;
1163 
1164   event_mask =
1165     GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
1166     GD_EVENT_OFF_BORDERS;
1167 
1168   /* create level drawing area */
1169   id = GADGET_ID_DRAWING_LEVEL;
1170   gi = CreateGadget(GDI_CUSTOM_ID, id,
1171 		    GDI_X, SX,
1172 		    GDI_Y, SY,
1173 		    GDI_TYPE, GD_TYPE_DRAWING_AREA,
1174 		    GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
1175 		    GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
1176 		    GDI_EVENT_MASK, event_mask,
1177 		    GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
1178 		    GDI_CALLBACK_ACTION, HandleDrawingAreas,
1179 		    GDI_END);
1180 
1181   if (gi == NULL)
1182     Error(ERR_EXIT, "cannot create gadget");
1183 
1184   level_editor_gadget[id] = gi;
1185 }
1186 
CreateTextInputGadgets()1187 static void CreateTextInputGadgets()
1188 {
1189   int i;
1190 
1191   for (i=0; i<ED_NUM_TEXTINPUT; i++)
1192   {
1193     Bitmap *gd_bitmap = pix[PIX_DOOR];
1194     int gd_x, gd_y;
1195     struct GadgetInfo *gi;
1196     unsigned long event_mask;
1197     char infotext[1024];
1198     int id = textinput_info[i].gadget_id;
1199 
1200     event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
1201 
1202     gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
1203     gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
1204 
1205     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
1206     infotext[MAX_INFOTEXT_LEN] = '\0';
1207 
1208     gi = CreateGadget(GDI_CUSTOM_ID, id,
1209 		      GDI_CUSTOM_TYPE_ID, i,
1210 		      GDI_INFO_TEXT, infotext,
1211 		      GDI_X, SX + textinput_info[i].x,
1212 		      GDI_Y, SY + textinput_info[i].y,
1213 		      GDI_TYPE, GD_TYPE_TEXTINPUT_ALPHANUMERIC,
1214 		      GDI_TEXT_VALUE, textinput_info[i].value,
1215 		      GDI_TEXT_SIZE, textinput_info[i].size,
1216 		      GDI_TEXT_FONT, FC_YELLOW,
1217 		      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
1218 		      GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
1219 		      GDI_BORDER_SIZE, ED_BORDER_SIZE,
1220 		      GDI_TEXTINPUT_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
1221 		      GDI_EVENT_MASK, event_mask,
1222 		      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
1223 		      GDI_CALLBACK_ACTION, HandleTextInputGadgets,
1224 		      GDI_END);
1225 
1226     if (gi == NULL)
1227       Error(ERR_EXIT, "cannot create gadget");
1228 
1229     level_editor_gadget[id] = gi;
1230   }
1231 }
1232 
CreateScrollbarGadgets()1233 static void CreateScrollbarGadgets()
1234 {
1235   int i;
1236 
1237   for (i=0; i<ED_NUM_SCROLLBARS; i++)
1238   {
1239     int id = scrollbar_info[i].gadget_id;
1240     Bitmap *gd_bitmap = pix[PIX_DOOR];
1241     int gd_x1, gd_x2, gd_y1, gd_y2;
1242     struct GadgetInfo *gi;
1243     int items_max, items_visible, item_position;
1244     unsigned long event_mask;
1245 
1246     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
1247     {
1248       items_max = elements_in_list / ED_ELEMENTLIST_BUTTONS_HORIZ;
1249       items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
1250       item_position = 0;
1251     }
1252     else
1253     {
1254       /* never reached (only one scrollbar) -- only to make gcc happy ;-) */
1255       items_max = 0;
1256       items_visible = 0;
1257       item_position = 0;
1258     }
1259 
1260     event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
1261 
1262     gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].xpos;
1263     gd_x2 = (gd_x1 - (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL ?
1264 		      scrollbar_info[i].height : scrollbar_info[i].width));
1265     gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1266     gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
1267 
1268     gi = CreateGadget(GDI_CUSTOM_ID, id,
1269 		      GDI_CUSTOM_TYPE_ID, i,
1270 		      GDI_INFO_TEXT, scrollbar_info[i].infotext,
1271 		      GDI_X, scrollbar_info[i].x,
1272 		      GDI_Y, scrollbar_info[i].y,
1273 		      GDI_WIDTH, scrollbar_info[i].width,
1274 		      GDI_HEIGHT, scrollbar_info[i].height,
1275 		      GDI_TYPE, scrollbar_info[i].type,
1276 		      GDI_SCROLLBAR_ITEMS_MAX, items_max,
1277 		      GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
1278 		      GDI_SCROLLBAR_ITEM_POSITION, item_position,
1279 		      GDI_STATE, GD_BUTTON_UNPRESSED,
1280 		      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
1281 		      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
1282 		      GDI_BORDER_SIZE, ED_BORDER_SIZE,
1283 		      GDI_EVENT_MASK, event_mask,
1284 		      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
1285 		      GDI_CALLBACK_ACTION, HandleControlButtons,
1286 		      GDI_END);
1287 
1288     if (gi == NULL)
1289       Error(ERR_EXIT, "cannot create gadget");
1290 
1291     level_editor_gadget[id] = gi;
1292   }
1293 }
1294 
CreateCheckbuttonGadgets()1295 static void CreateCheckbuttonGadgets()
1296 {
1297   Bitmap *gd_bitmap = pix[PIX_DOOR];
1298   struct GadgetInfo *gi;
1299   unsigned long event_mask;
1300   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
1301   int i;
1302 
1303   event_mask = GD_EVENT_PRESSED;
1304 
1305   gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
1306   gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
1307   gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
1308   gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
1309   gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
1310 
1311   for (i=0; i<ED_NUM_CHECKBUTTONS; i++)
1312   {
1313     int id = checkbutton_info[i].gadget_id;
1314 
1315     gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
1316 
1317     gi = CreateGadget(GDI_CUSTOM_ID, id,
1318 		      GDI_CUSTOM_TYPE_ID, i,
1319 		      GDI_INFO_TEXT, checkbutton_info[i].infotext,
1320 		      GDI_X, SX + checkbutton_info[i].x,
1321 		      GDI_Y, SY + checkbutton_info[i].y,
1322 		      GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
1323 		      GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
1324 		      GDI_TYPE, GD_TYPE_CHECK_BUTTON,
1325 		      GDI_CHECKED, *checkbutton_info[i].value,
1326 		      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
1327 		      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
1328 		      GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
1329 		      GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
1330 		      GDI_EVENT_MASK, event_mask,
1331 		      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
1332 		      GDI_CALLBACK_ACTION, HandleCheckbuttons,
1333 		      GDI_END);
1334 
1335     if (gi == NULL)
1336       Error(ERR_EXIT, "cannot create gadget");
1337 
1338     level_editor_gadget[id] = gi;
1339   }
1340 }
1341 
CreateLevelEditorGadgets()1342 void CreateLevelEditorGadgets()
1343 {
1344   CreateControlButtons();
1345   CreateCounterButtons();
1346   CreateDrawingArea();
1347   CreateTextInputGadgets();
1348   CreateScrollbarGadgets();
1349   CreateCheckbuttonGadgets();
1350 }
1351 
MapCounterButtons(int id)1352 static void MapCounterButtons(int id)
1353 {
1354   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
1355   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
1356   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
1357 }
1358 
MapControlButtons()1359 static void MapControlButtons()
1360 {
1361   int counter_id;
1362   int i;
1363 
1364   /* map toolbox buttons */
1365   for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
1366     MapGadget(level_editor_gadget[i]);
1367 
1368   /* map buttons to select elements */
1369   for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
1370     MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
1371 
1372   MapGadget(level_editor_gadget[GADGET_ID_DRAWING_ELEMENT_LEFT]);
1373   MapGadget(level_editor_gadget[GADGET_ID_DRAWING_ELEMENT_MIDDLE]);
1374   MapGadget(level_editor_gadget[GADGET_ID_DRAWING_ELEMENT_RIGHT]);
1375 
1376   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
1377   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
1378   MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
1379 
1380   /* map buttons to select level */
1381   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
1382   ModifyEditorCounterLimits(counter_id,
1383 			    leveldir_current->first_level,
1384 			    leveldir_current->last_level);
1385   ModifyEditorCounter(counter_id, *counterbutton_info[counter_id].value);
1386   MapCounterButtons(counter_id);
1387 }
1388 
MapDrawingArea(int id)1389 static void MapDrawingArea(int id)
1390 {
1391   MapGadget(level_editor_gadget[id]);
1392 }
1393 
MapTextInputGadget(int id)1394 static void MapTextInputGadget(int id)
1395 {
1396   MapGadget(level_editor_gadget[textinput_info[id].gadget_id]);
1397 }
1398 
MapCheckbuttonGadget(int id)1399 static void MapCheckbuttonGadget(int id)
1400 {
1401   MapGadget(level_editor_gadget[checkbutton_info[id].gadget_id]);
1402 }
1403 
MapMainDrawingArea()1404 static void MapMainDrawingArea()
1405 {
1406   MapDrawingArea(GADGET_ID_DRAWING_LEVEL);
1407 }
1408 
UnmapLevelEditorWindowGadgets()1409 void UnmapLevelEditorWindowGadgets()
1410 {
1411   int i;
1412 
1413   for (i=0; i<NUM_EDITOR_GADGETS; i++)
1414     if (level_editor_gadget[i]->x < SX + SXSIZE)
1415       UnmapGadget(level_editor_gadget[i]);
1416 }
1417 
UnmapLevelEditorGadgets()1418 void UnmapLevelEditorGadgets()
1419 {
1420   int i;
1421 
1422   for (i=0; i<NUM_EDITOR_GADGETS; i++)
1423     UnmapGadget(level_editor_gadget[i]);
1424 }
1425 
ResetUndoBuffer()1426 static void ResetUndoBuffer()
1427 {
1428   undo_buffer_position = -1;
1429   undo_buffer_steps = -1;
1430   CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
1431 }
1432 
DrawEditModeWindow()1433 static void DrawEditModeWindow()
1434 {
1435   if (edit_mode == ED_MODE_INFO)
1436     DrawLevelInfoWindow();
1437   else	/* edit_mode == ED_MODE_DRAWING */
1438     DrawDrawingWindow();
1439 }
1440 
getHiResLevelElement(int sx,int sy)1441 static int getHiResLevelElement(int sx, int sy)
1442 {
1443   int lx = sx / 2;
1444   int ly = sy / 2;
1445   int sx_offset = sx - 2 * lx;
1446   int sy_offset = sy - 2 * ly;
1447   int element = Feld[lx][ly];
1448   unsigned int bitmask = (sx_offset + 1) << (sy_offset * 2);
1449 
1450   if (IS_WALL(element))
1451   {
1452     if (element & bitmask)
1453       return WALL_BASE(element);
1454     else
1455       return EL_EMPTY;
1456   }
1457   else
1458     return element;
1459 }
1460 
PutHiResLevelElement(int sx,int sy,int hires_element,boolean change_level)1461 static void PutHiResLevelElement(int sx, int sy, int hires_element,
1462 				 boolean change_level)
1463 {
1464   int lx = sx / 2;
1465   int ly = sy / 2;
1466   int sx_offset = sx - 2 * lx;
1467   int sy_offset = sy - 2 * ly;
1468   int old_element = Feld[lx][ly];
1469   int new_element = hires_element;
1470   unsigned int old_bitmask = WALL_BITS(old_element);
1471   unsigned int new_bitmask = (sx_offset + 1) << (sy_offset * 2);
1472 
1473   if (new_element == EL_WALL_EMPTY)
1474     new_element = EL_EMPTY;
1475 
1476   if (IS_WALL(new_element))
1477   {
1478     new_element |= new_bitmask;
1479 
1480     if (IS_WALL(old_element))
1481       new_element |= old_bitmask;
1482   }
1483   else if (IS_WALL(old_element) && new_element == EL_EMPTY)
1484   {
1485     int new_element_changed = old_element & ~new_bitmask;
1486 
1487     if (WALL_BITS(new_element_changed) != 0)
1488       new_element = new_element_changed;
1489   }
1490 
1491   if (hires_element == EL_EMPTY && IS_WALL(old_element) && !change_level)
1492     DrawMiniElement(sx, sy, EL_EMPTY);
1493   else
1494     DrawElement(lx, ly, new_element);
1495 
1496   if (change_level)
1497     Feld[lx][ly] = new_element;
1498 }
1499 
WriteHiResLevelElement(int sx,int sy,int new_element)1500 static void WriteHiResLevelElement(int sx, int sy, int new_element)
1501 {
1502   PutHiResLevelElement(sx, sy, new_element, TRUE);
1503 }
1504 
1505 #if 0
1506 static void DrawHiResLevelElement(int sx, int sy, int new_element)
1507 {
1508   PutHiResLevelElement(sx, sy, new_element, FALSE);
1509 }
1510 #endif
1511 
LevelChanged()1512 static boolean LevelChanged()
1513 {
1514   boolean level_changed = FALSE;
1515   int x, y;
1516 
1517   for(y=0; y<lev_fieldy; y++)
1518     for(x=0; x<lev_fieldx; x++)
1519       if (Feld[x][y] != Ur[x][y])
1520 	level_changed = TRUE;
1521 
1522   return level_changed;
1523 }
1524 
LevelContainsPlayer()1525 static boolean LevelContainsPlayer()
1526 {
1527   boolean player_found = FALSE;
1528   int x, y;
1529 
1530   for(y=0; y<lev_fieldy; y++)
1531     for(x=0; x<lev_fieldx; x++)
1532       if (IS_MCDUFFIN(Feld[x][y]) || IS_LASER(Feld[x][y]))
1533 	player_found = TRUE;
1534 
1535   return player_found;
1536 }
1537 
DrawEditorLevel()1538 static void DrawEditorLevel()
1539 {
1540   DrawLevel();
1541 }
1542 
DrawLevelEd()1543 void DrawLevelEd()
1544 {
1545   CloseDoor(DOOR_CLOSE_ALL);
1546   OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
1547 
1548   if (level_editor_test_game)
1549   {
1550     int x, y;
1551 
1552     for(x=0; x<lev_fieldx; x++)
1553       for(y=0; y<lev_fieldy; y++)
1554 	Feld[x][y] = Ur[x][y];
1555 
1556     for(x=0; x<lev_fieldx; x++)
1557       for(y=0; y<lev_fieldy; y++)
1558 	Ur[x][y] = FieldBackup[x][y];
1559 
1560     level_editor_test_game = FALSE;
1561   }
1562   else
1563   {
1564     edit_mode = ED_MODE_DRAWING;
1565 
1566     ResetUndoBuffer();
1567     level_xpos = 0;
1568     level_ypos = 0;
1569   }
1570 
1571   /* copy default editor door content to main double buffer */
1572   BlitBitmap(pix[PIX_DOOR], drawto,
1573 	     DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
1574 
1575 #if 0
1576   /* draw mouse button brush elements */
1577   DrawMiniGraphicExt(drawto, gc,
1578 		     DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
1579 		     el2gfx(new_drawing_element[MB_LEFTBUTTON]));
1580   DrawMiniGraphicExt(drawto, gc,
1581 		     DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
1582 		     el2gfx(new_drawing_element[MB_MIDDLEBUTTON]));
1583   DrawMiniGraphicExt(drawto, gc,
1584 		     DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
1585 		     el2gfx(new_drawing_element[MB_RIGHTBUTTON]));
1586 #endif
1587 
1588 #if 0
1589   /* draw new control window */
1590   BlitBitmap(pix[PIX_DOOR], drawto,
1591 	     DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY);
1592 #endif
1593 
1594   redraw_mask |= REDRAW_ALL;
1595 
1596   MapControlButtons();
1597 
1598   /* copy actual editor door content to door double buffer for OpenDoor() */
1599   BlitBitmap(drawto, pix[PIX_DB_DOOR],
1600 	     DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1601 
1602   DrawEditModeWindow();
1603 
1604   /*
1605   FadeToFront();
1606   */
1607 
1608 
1609   OpenDoor(DOOR_OPEN_1);
1610 
1611   /*
1612   OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
1613   */
1614 }
1615 
ModifyEditorTextInput(int textinput_id,char * new_text)1616 static void ModifyEditorTextInput(int textinput_id, char *new_text)
1617 {
1618   int gadget_id = textinput_info[textinput_id].gadget_id;
1619   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1620 
1621   ModifyGadget(gi, GDI_TEXT_VALUE, new_text, GDI_END);
1622 }
1623 
ModifyEditorCounter(int counter_id,int new_value)1624 static void ModifyEditorCounter(int counter_id, int new_value)
1625 {
1626   int *counter_value = counterbutton_info[counter_id].value;
1627   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
1628   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1629 
1630   ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END);
1631 
1632   if (counter_value != NULL)
1633     *counter_value = gi->text.number_value;
1634 }
1635 
ModifyEditorCounterLimits(int counter_id,int min,int max)1636 static void ModifyEditorCounterLimits(int counter_id, int min, int max)
1637 {
1638   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
1639   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
1640 
1641   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
1642 }
1643 
PickDrawingElement(int button,int element)1644 static void PickDrawingElement(int button, int element)
1645 {
1646   int id = GADGET_ID_DRAWING_ELEMENT_LEFT + button - 1;
1647   struct GadgetInfo *gi = level_editor_gadget[id];
1648   struct GadgetDesign *gd = &gi->deco.design;
1649 
1650   if (button < 1 || button > 3)
1651     return;
1652 
1653   new_drawing_element[button] = element;
1654 
1655   getMiniGraphicSource(el2gfx(element), &gd->bitmap, &gd->x, &gd->y);
1656   ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
1657 
1658 #if 0
1659   if (button == 1)
1660   {
1661     new_element1 = element;
1662     DrawMiniGraphicExt(drawto, gc,
1663 		       DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
1664 		       el2gfx(new_element1));
1665   }
1666   else if (button == 2)
1667   {
1668     new_element2 = element;
1669     DrawMiniGraphicExt(drawto, gc,
1670 		       DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
1671 		       el2gfx(new_element2));
1672   }
1673   else
1674   {
1675     new_element3 = element;
1676     DrawMiniGraphicExt(drawto, gc,
1677 		       DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
1678 		       el2gfx(new_element3));
1679   }
1680 #endif
1681 
1682   redraw_mask |= REDRAW_DOOR_1;
1683 }
1684 
DrawDrawingWindow()1685 static void DrawDrawingWindow()
1686 {
1687   ClearWindow();
1688   UnmapLevelEditorWindowGadgets();
1689   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
1690   MapMainDrawingArea();
1691 }
1692 
DrawLevelInfoWindow()1693 static void DrawLevelInfoWindow()
1694 {
1695   char infotext[1024];
1696   int xoffset_above = 0;
1697   int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
1698   int xoffset_right = counter_xsize;
1699   int yoffset_right = ED_BORDER_SIZE;
1700   int xoffset_right2 = ED_CHECKBUTTON_XSIZE + 2 * ED_GADGET_DISTANCE;
1701   int yoffset_right2 = ED_BORDER_SIZE;
1702   int font_color = FC_GREEN;
1703   int i, x, y;
1704 
1705   if (level.auto_count_kettles)
1706   {
1707     level.kettles_needed = 0;
1708 
1709     for (y=0; y<lev_fieldy; y++)
1710       for(x=0; x<lev_fieldx; x++)
1711 	if (Feld[x][y] == EL_KETTLE)
1712 	  level.kettles_needed++;
1713   }
1714 
1715   ClearWindow();
1716   UnmapLevelEditorWindowGadgets();
1717 
1718   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS_YPOS,
1719 	   "Level Settings", FS_BIG, FC_YELLOW);
1720   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS,
1721 	   "Editor Settings", FS_BIG, FC_YELLOW);
1722 
1723   DrawTextF(ED_SETTINGS_XPOS, ED_COUNTER_YPOS(5) + yoffset_above,
1724 	    font_color, "Choose color components for laser:");
1725 
1726   /* draw counter gadgets */
1727   for (i=ED_COUNTER_ID_LEVEL_FIRST; i<=ED_COUNTER_ID_LEVEL_LAST; i++)
1728   {
1729     if (counterbutton_info[i].infotext_above)
1730     {
1731       x = counterbutton_info[i].x + xoffset_above;
1732       y = counterbutton_info[i].y + yoffset_above;
1733 
1734       sprintf(infotext, "%s:", counterbutton_info[i].infotext_above);
1735       infotext[MAX_INFOTEXT_LEN] = '\0';
1736       DrawTextF(x, y, font_color, infotext);
1737     }
1738 
1739     if (counterbutton_info[i].infotext_right)
1740     {
1741       x = counterbutton_info[i].x + xoffset_right;
1742       y = counterbutton_info[i].y + yoffset_right;
1743 
1744       sprintf(infotext, "%s", counterbutton_info[i].infotext_right);
1745       infotext[MAX_INFOTEXT_LEN] = '\0';
1746       DrawTextF(x, y, font_color, infotext);
1747     }
1748 
1749     ModifyEditorCounter(i, *counterbutton_info[i].value);
1750     MapCounterButtons(i);
1751   }
1752 
1753   /* draw text input gadgets */
1754   for (i=ED_TEXTINPUT_ID_LEVEL_FIRST; i<=ED_TEXTINPUT_ID_LEVEL_LAST; i++)
1755   {
1756     x = textinput_info[i].x + xoffset_above;
1757     y = textinput_info[i].y + yoffset_above;
1758 
1759     sprintf(infotext, "%s:", textinput_info[i].infotext);
1760     infotext[MAX_INFOTEXT_LEN] = '\0';
1761 
1762     DrawTextF(x, y, font_color, infotext);
1763     ModifyEditorTextInput(i, textinput_info[i].value);
1764     MapTextInputGadget(i);
1765   }
1766 
1767   /* draw checkbutton gadgets */
1768   for (i=ED_CHECKBUTTON_ID_LEVEL_FIRST; i<=ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
1769   {
1770     x = checkbutton_info[i].x + xoffset_right2;
1771     y = checkbutton_info[i].y + yoffset_right2;
1772 
1773     DrawTextF(x, y, font_color, checkbutton_info[i].text);
1774     ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
1775 		 GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
1776     MapCheckbuttonGadget(i);
1777   }
1778 }
1779 
DrawBrushElement(int lx,int ly,int element,boolean change_level)1780 static void DrawBrushElement(int lx, int ly, int element, boolean change_level)
1781 {
1782   /* if element is "empty" wall, fill it with its wall type */
1783   if (IS_WALL(element) && WALL_BITS(element) == 0)
1784     element |= 0x0f;
1785 
1786   DrawElement(lx, ly, (element < 0 ? Feld[lx][ly] : element));
1787 
1788   if (change_level)
1789     Feld[lx][ly] = element;
1790 }
1791 
DrawLineElement(int sx,int sy,int element,boolean change_level)1792 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
1793 {
1794   int lx = sx / 2;
1795   int ly = sy / 2;
1796   int old_lores_element = Feld[lx][ly];
1797 
1798 #if 0
1799   int lx = sx + level_xpos;
1800   int ly = sy + level_ypos;
1801 
1802   DrawMiniElement(sx, sy, (element < 0 ? Feld[lx][ly] : element));
1803 
1804   if (change_level)
1805     Feld[lx][ly] = element;
1806 #endif
1807 
1808   int old_element = getHiResLevelElement(sx, sy);
1809   int new_element = (element < 0 ? old_element : element);
1810 
1811   if ((IS_WALL(new_element) || IS_WALL(old_element)) && !change_level &&
1812       new_element != EL_WALL_EMPTY)
1813     editor.draw_walls_masked = TRUE;
1814 
1815   if (element < 0)
1816     DrawElement(lx, ly, old_lores_element);
1817   else
1818     PutHiResLevelElement(sx, sy, new_element, change_level);
1819 
1820   editor.draw_walls_masked = FALSE;
1821 }
1822 
DrawLine(int from_x,int from_y,int to_x,int to_y,int element,boolean change_level)1823 static void DrawLine(int from_x, int from_y, int to_x, int to_y,
1824 		     int element, boolean change_level)
1825 {
1826   if (from_y == to_y)			/* horizontal line */
1827   {
1828     int x;
1829     int y = from_y;
1830 
1831     if (from_x > to_x)
1832       swap_numbers(&from_x, &to_x);
1833 
1834     for (x=from_x; x<=to_x; x++)
1835       DrawLineElement(x, y, element, change_level);
1836   }
1837   else if (from_x == to_x)		/* vertical line */
1838   {
1839     int x = from_x;
1840     int y;
1841 
1842     if (from_y > to_y)
1843       swap_numbers(&from_y, &to_y);
1844 
1845     for (y=from_y; y<=to_y; y++)
1846       DrawLineElement(x, y, element, change_level);
1847   }
1848   else					/* diagonal line */
1849   {
1850     int len_x = ABS(to_x - from_x);
1851     int len_y = ABS(to_y - from_y);
1852     int x, y;
1853 
1854     if (len_y < len_x)			/* a < 1 */
1855     {
1856       float a = (float)len_y / (float)len_x;
1857 
1858       if (from_x > to_x)
1859 	swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
1860 
1861       for (x=0; x<=len_x; x++)
1862       {
1863 	y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1);
1864 	DrawLineElement(from_x + x, from_y + y, element, change_level);
1865       }
1866     }
1867     else				/* a >= 1 */
1868     {
1869       float a = (float)len_x / (float)len_y;
1870 
1871       if (from_y > to_y)
1872 	swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
1873 
1874       for (y=0; y<=len_y; y++)
1875       {
1876 	x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1);
1877 	DrawLineElement(from_x + x, from_y + y, element, change_level);
1878       }
1879     }
1880   }
1881 }
1882 
DrawRectangle(int from_x,int from_y,int to_x,int to_y,int element,boolean change_level)1883 static void DrawRectangle(int from_x, int from_y, int to_x, int to_y,
1884 			  int element, boolean change_level)
1885 {
1886   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
1887   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
1888   DrawLine(to_x, to_y, to_x, from_y, element, change_level);
1889   DrawLine(to_x, from_y, from_x, from_y, element, change_level);
1890 }
1891 
DrawFilledBox(int from_x,int from_y,int to_x,int to_y,int element,boolean change_level)1892 static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y,
1893 			  int element, boolean change_level)
1894 {
1895   int y;
1896 
1897   if (from_y > to_y)
1898     swap_number_pairs(&from_x, &from_y, &to_x, &to_y);
1899 
1900   for (y=from_y; y<=to_y; y++)
1901     DrawLine(from_x, y, to_x, y, element, change_level);
1902 }
1903 
DrawArcExt(int from_x,int from_y,int to_x2,int to_y2,int element,boolean change_level)1904 static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2,
1905 		       int element, boolean change_level)
1906 {
1907   int to_x = to_x2 - (to_x2 > from_x ? +1 : -1);
1908   int to_y = to_y2 - (to_y2 > from_y ? +1 : -1);
1909   int len_x = ABS(to_x - from_x);
1910   int len_y = ABS(to_y - from_y);
1911   int radius, x, y;
1912 
1913   radius = (int)(sqrt((float)(len_x * len_x + len_y * len_y)) + 0.5);
1914 
1915   /* not optimal (some points get drawn twice) but simple,
1916      and fast enough for the few points we are drawing */
1917 
1918   for (x=0; x<=radius; x++)
1919   {
1920     int sx, sy, lx, ly;
1921 
1922     y = (int)(sqrt((float)(radius * radius - x * x)) + 0.5);
1923 
1924     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
1925     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
1926     lx = sx / 2 + level_xpos;
1927     ly = sy / 2 + level_ypos;
1928 
1929     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
1930       DrawLineElement(sx, sy, element, change_level);
1931   }
1932 
1933   for (y=0; y<=radius; y++)
1934   {
1935     int sx, sy, lx, ly;
1936 
1937     x = (int)(sqrt((float)(radius * radius - y * y)) + 0.5);
1938 
1939     sx = from_x + x * (from_x < to_x2 ? +1 : -1);
1940     sy = from_y + y * (from_y < to_y2 ? +1 : -1);
1941     lx = sx / 2 + level_xpos;
1942     ly = sy / 2 + level_ypos;
1943 
1944     if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
1945       DrawLineElement(sx, sy, element, change_level);
1946   }
1947 }
1948 
DrawArc(int from_x,int from_y,int to_x,int to_y,int element,boolean change_level)1949 static void DrawArc(int from_x, int from_y, int to_x, int to_y,
1950 		    int element, boolean change_level)
1951 {
1952   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
1953   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
1954 
1955   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
1956 }
1957 
1958 #define DRAW_CIRCLES_BUTTON_AVAILABLE	0
1959 #if DRAW_CIRCLES_BUTTON_AVAILABLE
DrawCircle(int from_x,int from_y,int to_x,int to_y,int element,boolean change_level)1960 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
1961 		       int element, boolean change_level)
1962 {
1963   int to_x2 = to_x + (to_x < from_x ? -1 : +1);
1964   int to_y2 = to_y + (to_y > from_y ? +1 : -1);
1965   int mirror_to_x2 = from_x - (to_x2 - from_x);
1966   int mirror_to_y2 = from_y - (to_y2 - from_y);
1967 
1968   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
1969   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
1970   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
1971   DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
1972 }
1973 #endif
1974 
round_to_lores_grid(int * from_x,int * from_y,int * to_x,int * to_y)1975 static void round_to_lores_grid(int *from_x, int *from_y, int *to_x, int *to_y)
1976 {
1977   if (*from_x > *to_x)
1978     swap_numbers(from_x, to_x);
1979 
1980   if (*from_y > *to_y)
1981     swap_numbers(from_y, to_y);
1982 
1983   *from_x = (*from_x / 2) * 2;
1984   *from_y = (*from_y / 2) * 2;
1985   *to_x = (*to_x / 2) * 2 + 1;
1986   *to_y = (*to_y / 2) * 2 + 1;
1987 }
1988 
DrawAreaBorder(int from_x,int from_y,int to_x,int to_y)1989 static void DrawAreaBorder(int from_x, int from_y, int to_x, int to_y)
1990 {
1991   int from_sx, from_sy;
1992   int to_sx, to_sy;
1993 
1994   round_to_lores_grid(&from_x, &from_y, &to_x, &to_y);
1995 
1996   from_sx = SX + from_x * MINI_TILEX;
1997   from_sy = SY + from_y * MINI_TILEY;
1998   to_sx = SX + to_x * MINI_TILEX + MINI_TILEX - 1;
1999   to_sy = SY + to_y * MINI_TILEY + MINI_TILEY - 1;
2000 
2001   DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
2002   DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
2003   DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
2004   DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
2005 
2006   if (from_x == to_x && from_y == to_y)
2007     MarkTileDirty(from_x/2, from_y/2);
2008   else
2009     redraw_mask |= REDRAW_FIELD;
2010 }
2011 
SelectArea(int from_x,int from_y,int to_x,int to_y,int element,boolean change_level)2012 static void SelectArea(int from_x, int from_y, int to_x, int to_y,
2013 		       int element, boolean change_level)
2014 {
2015   round_to_lores_grid(&from_x, &from_y, &to_x, &to_y);
2016 
2017   if (element == -1 || change_level)
2018     DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE);
2019   else
2020     DrawAreaBorder(from_x, from_y, to_x, to_y);
2021 }
2022 
2023 /* values for CopyBrushExt() */
2024 #define CB_AREA_TO_BRUSH	0
2025 #define CB_BRUSH_TO_CURSOR	1
2026 #define CB_BRUSH_TO_LEVEL	2
2027 #define CB_DELETE_OLD_CURSOR	3
2028 
CopyBrushExt(int from_x,int from_y,int to_x,int to_y,int button,int mode)2029 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
2030 			 int button, int mode)
2031 {
2032   static short brush_buffer[MAX_ED_FIELDX][MAX_ED_FIELDY];
2033   static int brush_width, brush_height;
2034   static int last_cursor_x = -1, last_cursor_y = -1;
2035   static boolean delete_old_brush;
2036   int new_element = BUTTON_ELEMENT(button);
2037   int x, y;
2038 
2039   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
2040     return;
2041 
2042   if (mode == CB_AREA_TO_BRUSH)
2043   {
2044     int from_lx, from_ly;
2045 
2046     round_to_lores_grid(&from_x, &from_y, &to_x, &to_y);
2047 
2048     brush_width = to_x - from_x + 1;
2049     brush_height = to_y - from_y + 1;
2050 
2051     from_lx = from_x / 2 + level_xpos;
2052     from_ly = from_y / 2 + level_ypos;
2053 
2054     for (y=0; y<brush_height/2; y++)
2055     {
2056       for (x=0; x<brush_width/2; x++)
2057       {
2058 	brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
2059 
2060 	if (button != 1)
2061 	  DrawBrushElement(from_lx + x, from_ly + y, new_element, TRUE);
2062 #if 0
2063 	  DrawLineElement(from_x + x, from_y + y, new_element, TRUE);
2064 #endif
2065       }
2066     }
2067 
2068     if (button != 1)
2069       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2070 
2071     delete_old_brush = FALSE;
2072   }
2073   else if (mode == CB_BRUSH_TO_CURSOR || mode == CB_DELETE_OLD_CURSOR ||
2074 	   mode == CB_BRUSH_TO_LEVEL)
2075   {
2076     int from_x2 = (from_x / 2) * 2;
2077     int from_y2 = (from_y / 2) * 2;
2078     int cursor_x = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_x : from_x2);
2079     int cursor_y = (mode == CB_DELETE_OLD_CURSOR ? last_cursor_y : from_y2);
2080     int cursor_from_x = cursor_x - (brush_width / 4) * 2;
2081     int cursor_from_y = cursor_y - (brush_height / 4) * 2;
2082     int border_from_x = cursor_x, border_from_y = cursor_y;
2083     int border_to_x = cursor_x, border_to_y = cursor_y;
2084 
2085     if (mode != CB_DELETE_OLD_CURSOR && delete_old_brush)
2086       CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2087 
2088     if (!IN_ED_FIELD(cursor_x, cursor_y) ||
2089 	!IN_LEV_FIELD(cursor_x / 2 + level_xpos, cursor_y / 2 + level_ypos))
2090     {
2091       delete_old_brush = FALSE;
2092       return;
2093     }
2094 
2095     for (y=0; y<brush_height/2; y++)
2096     {
2097       for (x=0; x<brush_width/2; x++)
2098       {
2099 	int sx = cursor_from_x + x * 2;
2100 	int sy = cursor_from_y + y * 2;
2101 	int lx = sx / 2 + level_xpos;
2102 	int ly = sy / 2 + level_ypos;
2103 	boolean change_level = (mode == CB_BRUSH_TO_LEVEL);
2104 	int element = (mode == CB_DELETE_OLD_CURSOR ? -1 :
2105 		       mode == CB_BRUSH_TO_CURSOR || button == 1 ?
2106 		       brush_buffer[x][y] : new_element);
2107 
2108 	if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
2109 	{
2110 	  if (sx < border_from_x)
2111 	    border_from_x = sx;
2112 	  else if (sx > border_to_x)
2113 	    border_to_x = sx;
2114 	  if (sy < border_from_y)
2115 	    border_from_y = sy;
2116 	  else if (sy > border_to_y)
2117 	    border_to_y = sy;
2118 
2119 	  DrawBrushElement(lx, ly, element, change_level);
2120 #if 0
2121 	  DrawLineElement(sx, sy, element, change_level);
2122 #endif
2123 	}
2124       }
2125     }
2126 
2127     if (mode != CB_DELETE_OLD_CURSOR)
2128       DrawAreaBorder(border_from_x, border_from_y, border_to_x, border_to_y);
2129 
2130     last_cursor_x = cursor_x;
2131     last_cursor_y = cursor_y;
2132     delete_old_brush = TRUE;
2133   }
2134 }
2135 
CopyAreaToBrush(int from_x,int from_y,int to_x,int to_y,int button)2136 static void CopyAreaToBrush(int from_x, int from_y, int to_x, int to_y,
2137 			    int button)
2138 {
2139   CopyBrushExt(from_x, from_y, to_x, to_y, button, CB_AREA_TO_BRUSH);
2140 }
2141 
CopyBrushToLevel(int x,int y,int button)2142 static void CopyBrushToLevel(int x, int y, int button)
2143 {
2144   CopyBrushExt(x, y, 0, 0, button, CB_BRUSH_TO_LEVEL);
2145 }
2146 
CopyBrushToCursor(int x,int y)2147 static void CopyBrushToCursor(int x, int y)
2148 {
2149   CopyBrushExt(x, y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
2150 }
2151 
DeleteBrushFromCursor()2152 static void DeleteBrushFromCursor()
2153 {
2154   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
2155 }
2156 
FloodFillExt(short FillFeld[MAX_ED_FIELDX][MAX_ED_FIELDY],int from_x,int from_y,int fill_element)2157 static void FloodFillExt(short FillFeld[MAX_ED_FIELDX][MAX_ED_FIELDY],
2158 			 int from_x, int from_y, int fill_element)
2159 {
2160   int i,x,y;
2161   int old_element;
2162   static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
2163   static int safety = 0;
2164 
2165   /* check if starting field still has the desired content */
2166   if (FillFeld[from_x][from_y] == fill_element)
2167     return;
2168 
2169   safety++;
2170 
2171   if (safety > MAX_ED_FIELDX * MAX_ED_FIELDY)
2172     Error(ERR_EXIT, "Something went wrong in 'FloodFillExt()'. Please debug.");
2173 
2174   old_element = FillFeld[from_x][from_y];
2175   FillFeld[from_x][from_y] = fill_element;
2176 
2177   for(i=0;i<4;i++)
2178   {
2179     x = from_x + check[i][0];
2180     y = from_y + check[i][1];
2181 
2182     if (x >= 0 && x < MAX_ED_FIELDX && y >= 0 && y < MAX_ED_FIELDY &&
2183 	FillFeld[x][y] == old_element)
2184       FloodFillExt(FillFeld, x, y, fill_element);
2185   }
2186 
2187   safety--;
2188 }
2189 
FloodFill(int from_x,int from_y,int fill_element)2190 static void FloodFill(int from_x, int from_y, int fill_element)
2191 {
2192   short FillFeld[MAX_ED_FIELDX][MAX_ED_FIELDY];
2193   int x, y;
2194 
2195   for (x=0; x<MAX_ED_FIELDX; x++) for (y=0; y<MAX_ED_FIELDY; y++)
2196     FillFeld[x][y] = getHiResLevelElement(x, y);
2197 
2198   FloodFillExt(FillFeld, from_x, from_y, fill_element);
2199 
2200   for (x=0; x<MAX_ED_FIELDX; x++) for (y=0; y<MAX_ED_FIELDY; y++)
2201     if (FillFeld[x][y] == fill_element)
2202       PutHiResLevelElement(x, y, FillFeld[x][y], TRUE);
2203 }
2204 
2205 #if 0
2206 static void OLD_FloodFill(int from_x, int from_y, int fill_element)
2207 {
2208   int i;
2209   int old_hires_element = getHiResLevelElement(from_x, from_y);
2210   int old_lores_element = Feld[from_x / 2][from_y / 2];
2211   static int check[4][2] = { {-1,0}, {0,-1}, {1,0}, {0,1} };
2212   static int safety = 0;
2213 
2214   /* check if starting field already has the desired content */
2215   if (old_hires_element == fill_element)
2216     return;
2217 
2218   safety++;
2219 
2220   if (safety > ed_fieldx * ed_fieldy)
2221     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
2222 
2223   if (IS_WALL(fill_element) ||
2224       (fill_element == EL_EMPTY && IS_WALL(old_hires_element)))
2225   {
2226     if (IS_WALL(old_hires_element))
2227       PutHiResLevelElement(from_x, from_y, fill_element, TRUE);
2228     else
2229       Feld[from_x / 2][from_y / 2] = fill_element | 0x0f;
2230 
2231     /* do flood fill for all four possible fields */
2232     for(i=0;i<4;i++)
2233     {
2234       int from_xx = (from_x / 2) * 2 + i/2;
2235       int from_yy = (from_y / 2) * 2 + i%2;
2236       int j;
2237 
2238       if ((fill_element != EL_EMPTY &&
2239 	   getHiResLevelElement(from_xx, from_yy) == fill_element &&
2240 	   (getHiResLevelElement(from_xx, from_y) != EL_EMPTY ||
2241 	    getHiResLevelElement(from_x, from_yy) != EL_EMPTY)) ||
2242 	  (fill_element == EL_EMPTY && from_xx == from_x && from_yy == from_y))
2243       {
2244 	for(j=0;j<4;j++)
2245 	{
2246 	  int next_x = from_xx + check[j][0];
2247 	  int next_y = from_yy + check[j][1];
2248 
2249 	  if (IN_ED_FIELD(next_x, next_y) &&
2250 	      getHiResLevelElement(next_x, next_y) == old_hires_element)
2251 	    FloodFill(next_x, next_y, fill_element);
2252 	}
2253       }
2254     }
2255   }
2256   else
2257   {
2258     int lx = from_x / 2;
2259     int ly = from_y / 2;
2260 
2261     Feld[lx][ly] = fill_element;
2262 
2263     if (!IS_WALL(old_lores_element) || WALL_BITS(old_lores_element) == 0x0f)
2264     {
2265       for(i=0;i<4;i++)
2266       {
2267 	int next_lx = lx + check[i][0];
2268 	int next_ly = ly + check[i][1];
2269 	int next_x = next_lx * 2;
2270 	int next_y = next_ly * 2;
2271 
2272 	if (IN_LEV_FIELD(next_lx, next_ly) &&
2273 	    Feld[next_lx][next_ly] == old_lores_element)
2274 	  FloodFill(next_x, next_y, fill_element);
2275       }
2276     }
2277   }
2278 
2279 #if 0
2280   PutHiResLevelElement(from_x, from_y, fill_element, TRUE);
2281 
2282   for(i=0;i<4;i++)
2283   {
2284     int sx = from_x + check[i][0];
2285     int sy = from_y + check[i][1];
2286     int lx, ly;
2287 
2288     if (!IS_WALL(fill_element) && sx/2 == from_x/2 && sy/2 == from_y/2)
2289     {
2290       sx = from_x + 2 * check[i][0];
2291       sy = from_y + 2 * check[i][1];
2292     }
2293 
2294     lx = sx / 2;
2295     ly = sy / 2;
2296 
2297     /*
2298     printf("%d,%d\n", sx, sy);
2299     */
2300 
2301     if (IN_LEV_FIELD(lx, ly) && getHiResLevelElement(sx, sy) == old_element)
2302       FloodFill(sx, sy, fill_element);
2303   }
2304 #endif
2305 
2306   safety--;
2307 }
2308 #endif
2309 
CopyLevelToUndoBuffer(int mode)2310 static void CopyLevelToUndoBuffer(int mode)
2311 {
2312   static boolean accumulated_undo = FALSE;
2313   boolean new_undo_buffer_position = TRUE;
2314   int x, y;
2315 
2316   switch (mode)
2317   {
2318     case UNDO_IMMEDIATE:
2319       accumulated_undo = FALSE;
2320       break;
2321 
2322     case UNDO_ACCUMULATE:
2323       if (accumulated_undo)
2324 	new_undo_buffer_position = FALSE;
2325       accumulated_undo = TRUE;
2326       break;
2327 
2328     default:
2329       break;
2330   }
2331 
2332   if (new_undo_buffer_position)
2333   {
2334     /* new position in undo buffer ring */
2335     undo_buffer_position = (undo_buffer_position + 1) % NUM_UNDO_STEPS;
2336 
2337     if (undo_buffer_steps < NUM_UNDO_STEPS - 1)
2338       undo_buffer_steps++;
2339   }
2340 
2341   for(x=0; x<lev_fieldx; x++)
2342     for(y=0; y<lev_fieldy; y++)
2343       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
2344 
2345 #if 0
2346 #ifdef DEBUG
2347   printf("level saved to undo buffer %d\n", undo_buffer_position);
2348 #endif
2349 #endif
2350 }
2351 
WrapLevel(int dx,int dy)2352 void WrapLevel(int dx, int dy)
2353 {
2354   int wrap_dx = lev_fieldx - dx;
2355   int wrap_dy = lev_fieldy - dy;
2356   int x, y;
2357 
2358   for(x=0; x<lev_fieldx; x++)
2359     for(y=0; y<lev_fieldy; y++)
2360       FieldBackup[x][y] = Feld[x][y];
2361 
2362   for(x=0; x<lev_fieldx; x++)
2363     for(y=0; y<lev_fieldy; y++)
2364       Feld[x][y] =
2365 	FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
2366 
2367   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
2368   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
2369 }
2370 
HandleDrawingAreas(struct GadgetInfo * gi)2371 static void HandleDrawingAreas(struct GadgetInfo *gi)
2372 {
2373   static boolean started_inside_drawing_area = FALSE;
2374   int id = gi->custom_id;
2375   boolean button_press_event;
2376   boolean button_release_event;
2377   boolean inside_drawing_area = !gi->event.off_borders;
2378   boolean draw_level = (id == GADGET_ID_DRAWING_LEVEL);
2379   int actual_drawing_function;
2380   int button = gi->event.button;
2381   int new_element = BUTTON_ELEMENT(button);
2382   int sx = gi->event.x, sy = gi->event.y;
2383   int min_sx = 0, min_sy = 0;
2384   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
2385   int lx = 0, ly = 0;
2386   int min_lx = 0, min_ly = 0;
2387   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
2388   int x, y;
2389 
2390   /* handle info callback for each invocation of action callback */
2391   gi->callback_info(gi);
2392 
2393   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
2394   button_release_event = (gi->event.type == GD_EVENT_RELEASED);
2395 
2396   /* make sure to stay inside drawing area boundaries */
2397   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
2398   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
2399 
2400   if (draw_level)
2401   {
2402     /* get positions inside level field */
2403     lx = sx / 2;
2404     ly = sy / 2;
2405 
2406     if (!IN_LEV_FIELD(lx, ly))
2407       inside_drawing_area = FALSE;
2408 
2409     /* make sure to stay inside level field boundaries */
2410     lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
2411     ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
2412 
2413 #if 0
2414     /* correct drawing area positions accordingly */
2415     sx = lx - level_xpos;
2416     sy = ly - level_ypos;
2417 #endif
2418   }
2419 
2420   if (button_press_event)
2421     started_inside_drawing_area = inside_drawing_area;
2422 
2423   if (!started_inside_drawing_area)
2424     return;
2425 
2426   if (!button && !button_release_event)
2427     return;
2428 
2429   /* automatically switch to 'single item' drawing mode, if needed */
2430   actual_drawing_function =
2431     (draw_level ? drawing_function : GADGET_ID_SINGLE_ITEMS);
2432 
2433   switch (actual_drawing_function)
2434   {
2435     case GADGET_ID_SINGLE_ITEMS:
2436       if (button_release_event)
2437       {
2438 	CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2439 
2440 	if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
2441 	    !inside_drawing_area)
2442 	  DeleteBrushFromCursor();
2443       }
2444 
2445       if (!button)
2446 	break;
2447 
2448       if (draw_with_brush)
2449       {
2450 	if (!button_release_event)
2451 	  CopyBrushToLevel(sx, sy, button);
2452       }
2453       else if (new_element != Feld[lx][ly])
2454       {
2455 	if (IS_MCDUFFIN(new_element) || IS_LASER(new_element))
2456 	{
2457 	  /* remove player at old position */
2458 	  for(y=0; y<lev_fieldy; y++)
2459 	  {
2460 	    for(x=0; x<lev_fieldx; x++)
2461 	    {
2462 	      if (IS_MCDUFFIN(Feld[x][y]) || IS_LASER(Feld[x][y]))
2463 	      {
2464 		Feld[x][y] = EL_EMPTY;
2465 		if (x - level_xpos >= 0 && x - level_xpos < ed_fieldx &&
2466 		    y - level_ypos >= 0 && y - level_ypos < ed_fieldy)
2467 		  DrawElement(x - level_xpos, y - level_ypos, EL_EMPTY);
2468 	      }
2469 	    }
2470 	  }
2471 	}
2472 
2473 	WriteHiResLevelElement(sx, sy, new_element);
2474       }
2475       break;
2476 
2477     case GADGET_ID_LINE:
2478     case GADGET_ID_ARC:
2479     case GADGET_ID_RECTANGLE:
2480     case GADGET_ID_FILLED_BOX:
2481     case GADGET_ID_GRAB_BRUSH:
2482       {
2483 	static int last_sx = -1;
2484 	static int last_sy = -1;
2485 	static int start_sx = -1;
2486 	static int start_sy = -1;
2487 	void (*draw_func)(int, int, int, int, int, boolean);
2488 
2489 	if (drawing_function == GADGET_ID_LINE)
2490 	  draw_func = DrawLine;
2491 	else if (drawing_function == GADGET_ID_ARC)
2492 	  draw_func = DrawArc;
2493 	else if (drawing_function == GADGET_ID_RECTANGLE)
2494 	  draw_func = DrawRectangle;
2495 	else if (drawing_function == GADGET_ID_FILLED_BOX)
2496 	  draw_func = DrawFilledBox;
2497 	else /* (drawing_function == GADGET_ID_GRAB_BRUSH) */
2498 	  draw_func = SelectArea;
2499 
2500 	if (button_press_event)
2501 	{
2502 	  draw_func(sx, sy, sx, sy, new_element, FALSE);
2503 	  start_sx = last_sx = sx;
2504 	  start_sy = last_sy = sy;
2505 	}
2506 	else if (button_release_event)
2507 	{
2508 	  draw_func(start_sx, start_sy, sx, sy, new_element, TRUE);
2509 	  if (drawing_function == GADGET_ID_GRAB_BRUSH)
2510 	  {
2511 	    CopyAreaToBrush(start_sx, start_sy, sx, sy, button);
2512 	    CopyBrushToCursor(sx, sy);
2513 	    ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS],
2514 			  MB_LEFTBUTTON);
2515 	    draw_with_brush = TRUE;
2516 	  }
2517 	  else
2518 	    CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2519 	}
2520 	else if (last_sx != sx || last_sy != sy)
2521 	{
2522 #if 0
2523 	  draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
2524 	  draw_func(start_sx, start_sy, sx, sy, EL_EMPTY, FALSE);
2525 	  draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
2526 #else
2527 	  draw_func(start_sx, start_sy, last_sx, last_sy, -1, FALSE);
2528 	  if (IS_WALL(new_element))	/* clear wall background */
2529 	    draw_func(start_sx, start_sy, sx, sy, EL_WALL_EMPTY, FALSE);
2530 	  draw_func(start_sx, start_sy, sx, sy, new_element, FALSE);
2531 #endif
2532 	  last_sx = sx;
2533 	  last_sy = sy;
2534 	}
2535       }
2536       break;
2537 
2538     case GADGET_ID_FLOOD_FILL:
2539       if (button_press_event && Feld[lx][ly] != new_element)
2540       {
2541 	FloodFill(sx, sy, new_element);
2542 	DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
2543 	CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
2544       }
2545       break;
2546 
2547     case GADGET_ID_PICK_ELEMENT:
2548       if (button_release_event)
2549 	ClickOnGadget(level_editor_gadget[last_drawing_function],
2550 		      MB_LEFTBUTTON);
2551       else
2552 	PickDrawingElement(button, getHiResLevelElement(sx, sy));
2553       break;
2554 
2555     default:
2556       break;
2557   }
2558 }
2559 
HandleCounterButtons(struct GadgetInfo * gi)2560 static void HandleCounterButtons(struct GadgetInfo *gi)
2561 {
2562   int gadget_id = gi->custom_id;
2563   int counter_id = gi->custom_type_id;
2564   int button = gi->event.button;
2565   int *counter_value = counterbutton_info[counter_id].value;
2566   int step = BUTTON_STEPSIZE(button) *
2567     (gadget_id == counterbutton_info[counter_id].gadget_id_down ? -1 : +1);
2568 
2569   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
2570   {
2571     boolean pressed = (gi->event.type == GD_EVENT_PRESSED);
2572     boolean released = (gi->event.type == GD_EVENT_RELEASED);
2573     boolean level_changed = LevelChanged();
2574 
2575     if ((level_changed && pressed) || (!level_changed && released))
2576       return;
2577 
2578     if (level_changed && !Request("Level has changed! Discard changes ?",
2579 				  REQ_ASK))
2580     {
2581       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
2582 	ModifyEditorCounter(counter_id, *counter_value);
2583       return;
2584     }
2585   }
2586 
2587   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
2588     *counter_value = gi->text.number_value;
2589   else
2590     ModifyEditorCounter(counter_id, *counter_value + step);
2591 
2592   switch (counter_id)
2593   {
2594     case ED_COUNTER_ID_SELECT_LEVEL:
2595       LoadLevel(level_nr);
2596       ResetUndoBuffer();
2597       DrawEditModeWindow();
2598       break;
2599 
2600     default:
2601       break;
2602   }
2603 }
2604 
HandleTextInputGadgets(struct GadgetInfo * gi)2605 static void HandleTextInputGadgets(struct GadgetInfo *gi)
2606 {
2607   strcpy(textinput_info[gi->custom_type_id].value, gi->text.value);
2608 }
2609 
HandleCheckbuttons(struct GadgetInfo * gi)2610 static void HandleCheckbuttons(struct GadgetInfo *gi)
2611 {
2612   *checkbutton_info[gi->custom_type_id].value ^= TRUE;
2613 
2614   if (gi->custom_id == GADGET_ID_AUTO_COUNT && level.auto_count_kettles)
2615   {
2616     int x, y;
2617 
2618     level.kettles_needed = 0;
2619 
2620     for (y=0; y<lev_fieldy; y++)
2621       for(x=0; x<lev_fieldx; x++)
2622 	if (Feld[x][y] == EL_KETTLE)
2623 	  level.kettles_needed++;
2624 
2625     ModifyEditorCounter(ED_COUNTER_ID_LEVEL_COLLECT, level.kettles_needed);
2626   }
2627 }
2628 
HandleControlButtons(struct GadgetInfo * gi)2629 static void HandleControlButtons(struct GadgetInfo *gi)
2630 {
2631   int id = gi->custom_id;
2632   int button = gi->event.button;
2633   int step = BUTTON_STEPSIZE(button);
2634   int new_element = BUTTON_ELEMENT(button);
2635   int i, x, y;
2636 
2637   switch (id)
2638   {
2639     case GADGET_ID_SCROLL_LIST_UP:
2640     case GADGET_ID_SCROLL_LIST_DOWN:
2641     case GADGET_ID_SCROLL_LIST_VERTICAL:
2642       if (id == GADGET_ID_SCROLL_LIST_VERTICAL)
2643 	element_shift = gi->event.item_position * ED_ELEMENTLIST_BUTTONS_HORIZ;
2644       else
2645       {
2646 	step *= (id == GADGET_ID_SCROLL_LIST_UP ? -1 : +1);
2647 	element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
2648 
2649 	if (element_shift < 0)
2650 	  element_shift = 0;
2651 	if (element_shift > elements_in_list - ED_NUM_ELEMENTLIST_BUTTONS)
2652 	  element_shift = elements_in_list - ED_NUM_ELEMENTLIST_BUTTONS;
2653 
2654 	ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
2655 		     GDI_SCROLLBAR_ITEM_POSITION,
2656 		     element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
2657       }
2658 
2659       for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
2660       {
2661 	int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
2662 	struct GadgetInfo *gi = level_editor_gadget[gadget_id];
2663 	struct GadgetDesign *gd = &gi->deco.design;
2664 	int element = editor_element[element_shift + i];
2665 
2666 	UnmapGadget(gi);
2667 	getMiniGraphicSource(el2gfx(element), &gd->bitmap, &gd->x, &gd->y);
2668 	ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
2669 	MapGadget(gi);
2670       }
2671       break;
2672 
2673     case GADGET_ID_WRAP_LEFT:
2674       WrapLevel(-step, 0);
2675       break;
2676 
2677     case GADGET_ID_WRAP_RIGHT:
2678       WrapLevel(step, 0);
2679       break;
2680 
2681     case GADGET_ID_WRAP_UP:
2682       WrapLevel(0, -step);
2683       break;
2684 
2685     case GADGET_ID_WRAP_DOWN:
2686       WrapLevel(0, step);
2687       break;
2688 
2689     case GADGET_ID_SINGLE_ITEMS:
2690     case GADGET_ID_LINE:
2691     case GADGET_ID_ARC:
2692     case GADGET_ID_RECTANGLE:
2693     case GADGET_ID_FILLED_BOX:
2694     case GADGET_ID_FLOOD_FILL:
2695     case GADGET_ID_GRAB_BRUSH:
2696     case GADGET_ID_PICK_ELEMENT:
2697       last_drawing_function = drawing_function;
2698       drawing_function = id;
2699       draw_with_brush = FALSE;
2700       break;
2701 
2702     case GADGET_ID_UNDO:
2703       if (undo_buffer_steps == 0)
2704       {
2705 	Request("Undo buffer empty !", REQ_CONFIRM);
2706 	break;
2707       }
2708 
2709       undo_buffer_position =
2710 	(undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
2711       undo_buffer_steps--;
2712 
2713       for(x=0; x<lev_fieldx; x++)
2714 	for(y=0; y<lev_fieldy; y++)
2715 	  Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
2716       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos,level_ypos);
2717 
2718 #if 0
2719 #ifdef DEBUG
2720   printf("level restored from undo buffer %d\n", undo_buffer_position);
2721 #endif
2722 #endif
2723       break;
2724 
2725     case GADGET_ID_INFO:
2726       if (edit_mode != ED_MODE_INFO)
2727       {
2728 	DrawLevelInfoWindow();
2729 	edit_mode = ED_MODE_INFO;
2730       }
2731       else
2732       {
2733 	DrawDrawingWindow();
2734 	edit_mode = ED_MODE_DRAWING;
2735       }
2736       break;
2737 
2738     case GADGET_ID_CLEAR:
2739       for(x=0; x<MAX_LEV_FIELDX; x++)
2740 	for(y=0; y<MAX_LEV_FIELDY; y++)
2741 	  Feld[x][y] = (button == 1 ? EL_EMPTY : new_element);
2742       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
2743 
2744       DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
2745       break;
2746 
2747     case GADGET_ID_SAVE:
2748       if (leveldir_current->readonly)
2749       {
2750 	Request("This level is read only !", REQ_CONFIRM);
2751 	break;
2752       }
2753 
2754       if (!LevelContainsPlayer)
2755 	Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
2756       else
2757       {
2758 	if (Request("Save this level and kill the old ?", REQ_ASK))
2759 	{
2760 	  for(x=0; x<lev_fieldx; x++)
2761 	    for(y=0; y<lev_fieldy; y++)
2762 	      Ur[x][y] = Feld[x][y];
2763 	  SaveLevel(level_nr);
2764 	}
2765       }
2766       break;
2767 
2768     case GADGET_ID_TEST:
2769       if (!LevelContainsPlayer)
2770 	Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
2771       else
2772       {
2773 	for(x=0; x<lev_fieldx; x++)
2774 	  for(y=0; y<lev_fieldy; y++)
2775 	    FieldBackup[x][y] = Ur[x][y];
2776 
2777 	for(x=0; x<lev_fieldx; x++)
2778 	  for(y=0; y<lev_fieldy; y++)
2779 	    Ur[x][y] = Feld[x][y];
2780 
2781 	UnmapLevelEditorGadgets();
2782 
2783 	CloseDoor(DOOR_CLOSE_ALL);
2784 
2785 	level_editor_test_game = TRUE;
2786 	game_status = PLAYING;
2787 
2788 	InitGame();
2789       }
2790       break;
2791 
2792     case GADGET_ID_EXIT:
2793       if (!LevelChanged() ||
2794 	  Request("Level has changed! Exit without saving ?",
2795 		  REQ_ASK | REQ_STAY_OPEN))
2796       {
2797 	CloseDoor(DOOR_CLOSE_1);
2798 
2799 	/*
2800 	CloseDoor(DOOR_CLOSE_ALL);
2801 	*/
2802 
2803 	game_status = MAINMENU;
2804 	DrawMainMenu();
2805       }
2806       else
2807       {
2808 	CloseDoor(DOOR_CLOSE_1);
2809 	BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2810 		   DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2811 		   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2812 	OpenDoor(DOOR_OPEN_1);
2813       }
2814       break;
2815 
2816     case GADGET_ID_DRAWING_ELEMENT_LEFT:
2817     case GADGET_ID_DRAWING_ELEMENT_MIDDLE:
2818     case GADGET_ID_DRAWING_ELEMENT_RIGHT:
2819     {
2820       int new_element_nr = id - GADGET_ID_DRAWING_ELEMENT_LEFT + 1;
2821       int rotated_element =
2822 	get_rotated_element(new_drawing_element[new_element_nr],
2823 			    BUTTON_ROTATION(button));
2824 
2825       PickDrawingElement(new_element_nr, rotated_element);
2826       HandleEditorGadgetInfoText(gi);
2827       break;
2828     }
2829 
2830     default:
2831       if (id >= GADGET_ID_ELEMENTLIST_FIRST &&
2832 	  id <= GADGET_ID_ELEMENTLIST_LAST)
2833       {
2834 	int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
2835 	int new_element = editor_element[element_position + element_shift];
2836 
2837 	PickDrawingElement(button, new_element);
2838 
2839 	if (drawing_function == GADGET_ID_PICK_ELEMENT)
2840 	  ClickOnGadget(level_editor_gadget[last_drawing_function],
2841 			MB_LEFTBUTTON);
2842       }
2843 #ifdef DEBUG
2844       else if (gi->event.type == GD_EVENT_PRESSED)
2845 	printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id);
2846       else if (gi->event.type == GD_EVENT_RELEASED)
2847 	printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id);
2848       else if (gi->event.type == GD_EVENT_MOVING)
2849 	printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id);
2850       else
2851 	printf("default: HandleControlButtons: ? (id == %d)\n", id);
2852 #endif
2853       break;
2854   }
2855 }
2856 
HandleLevelEditorKeyInput(Key key)2857 void HandleLevelEditorKeyInput(Key key)
2858 {
2859   char letter = getCharFromKey(key);
2860   int button = MB_LEFTBUTTON;
2861 
2862   if (button_status == MB_RELEASED)
2863   {
2864     int i, id;
2865 
2866     switch (key)
2867     {
2868       case KSYM_Page_Up:
2869 	id = GADGET_ID_SCROLL_LIST_UP;
2870 	button = MB_RIGHTBUTTON;
2871 	break;
2872       case KSYM_Page_Down:
2873 	id = GADGET_ID_SCROLL_LIST_DOWN;
2874 	button = MB_RIGHTBUTTON;
2875 	break;
2876 
2877       default:
2878 	id = GADGET_ID_NONE;
2879 	break;
2880     }
2881 
2882     if (id != GADGET_ID_NONE)
2883       ClickOnGadget(level_editor_gadget[id], button);
2884     else if (letter == '.')
2885       ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
2886     else if (key == KSYM_space || key == KSYM_Return)
2887       ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
2888     else
2889       for (i=0; i<ED_NUM_CTRL_BUTTONS; i++)
2890 	if (letter && letter == control_info[i].shortcut)
2891 	  if (!anyTextGadgetActive())
2892 	    ClickOnGadget(level_editor_gadget[i], button);
2893   }
2894 }
2895 
ClearEditorGadgetInfoText()2896 void ClearEditorGadgetInfoText()
2897 {
2898   int x;
2899 
2900   if (edit_mode == ED_MODE_DRAWING)
2901     for (x=0; x<lev_fieldx; x++)
2902       DrawElement(x, lev_fieldy-1, Feld[x][lev_fieldy-1]);
2903   else
2904     ClearRectangle(drawto,
2905 		   INFOTEXT_XPOS, INFOTEXT_YPOS,
2906 		   INFOTEXT_XSIZE, INFOTEXT_YSIZE);
2907 
2908   redraw_mask |= REDRAW_FIELD;
2909 }
2910 
HandleEditorGadgetInfoText(void * ptr)2911 void HandleEditorGadgetInfoText(void *ptr)
2912 {
2913   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
2914   char infotext[MAX_INFOTEXT_LEN + 1];
2915   char shortcut[MAX_INFOTEXT_LEN + 1];
2916 
2917   ClearEditorGadgetInfoText();
2918 
2919   /* misuse this function to delete brush cursor, if needed */
2920   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
2921     DeleteBrushFromCursor();
2922 
2923   if (gi == NULL || gi->info_text == NULL)
2924     return;
2925 
2926   strncpy(infotext, gi->info_text, MAX_INFOTEXT_LEN);
2927   infotext[MAX_INFOTEXT_LEN] = '\0';
2928 
2929   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
2930   {
2931     int key = control_info[gi->custom_id].shortcut;
2932 
2933     if (key)
2934     {
2935       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)	/* special case 1 */
2936 	sprintf(shortcut, " ('.' or '%c')", key);
2937       else if (gi->custom_id == GADGET_ID_TEST)		/* special case 2 */
2938 	sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
2939       else						/* normal case */
2940 	sprintf(shortcut, " ('%s%c')",
2941 		(key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
2942 
2943       if (strlen(infotext) + strlen(shortcut) <= MAX_INFOTEXT_LEN)
2944 	strcat(infotext, shortcut);
2945     }
2946   }
2947 
2948   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FS_SMALL, FC_YELLOW);
2949 }
2950 
HandleDrawingAreaInfo(struct GadgetInfo * gi)2951 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
2952 {
2953 #if 0
2954   static int start_lx, start_ly;
2955   char *infotext;
2956 #endif
2957   int id = gi->custom_id;
2958   int sx = gi->event.x;
2959   int sy = gi->event.y;
2960   int lx = sx / 2 + level_xpos;
2961   int ly = sy / 2 + level_ypos;
2962   int min_sx = 0, min_sy = 0;
2963   int max_sx = gi->drawing.area_xsize - 1;
2964   int max_sy = gi->drawing.area_ysize - 1;
2965 
2966   ClearEditorGadgetInfoText();
2967 
2968   /* make sure to stay inside drawing area boundaries */
2969   sx = (sx < min_sx ? min_sx : sx > max_sx ? max_sx : sx);
2970   sy = (sy < min_sy ? min_sy : sy > max_sy ? max_sy : sy);
2971 
2972   if (id == GADGET_ID_DRAWING_LEVEL)
2973   {
2974     if (button_status)
2975     {
2976       int min_lx = 0, min_ly = 0;
2977       int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
2978 
2979       /* get positions inside level field */
2980       lx = sx / 2 + level_xpos;
2981       ly = sy / 2 + level_ypos;
2982 
2983       /* make sure to stay inside level field boundaries */
2984       lx = (lx < min_lx ? min_lx : lx > max_lx ? max_lx : lx);
2985       ly = (ly < min_ly ? min_ly : ly > max_ly ? max_ly : ly);
2986 
2987 #if 0
2988       /* correct drawing area positions accordingly */
2989       sx = lx - level_xpos;
2990       sy = ly - level_ypos;
2991 #endif
2992     }
2993 
2994 #if 0
2995     if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
2996     {
2997       if (button_status)	/* if (gi->state == GD_BUTTON_PRESSED) */
2998       {
2999 	if (gi->event.type == GD_EVENT_PRESSED)
3000 	{
3001 	  start_lx = lx;
3002 	  start_ly = ly;
3003 	}
3004 
3005 	switch (drawing_function)
3006 	{
3007 	  case GADGET_ID_SINGLE_ITEMS:
3008 	    infotext = "Drawing single items";
3009 	    break;
3010       	  case GADGET_ID_LINE:
3011 	    infotext = "Drawing line";
3012 	    break;
3013       	  case GADGET_ID_ARC:
3014 	    infotext = "Drawing arc";
3015 	    break;
3016       	  case GADGET_ID_RECTANGLE:
3017 	    infotext = "Drawing rectangle";
3018 	    break;
3019       	  case GADGET_ID_FILLED_BOX:
3020 	    infotext = "Drawing filled box";
3021 	    break;
3022       	  case GADGET_ID_FLOOD_FILL:
3023 	    infotext = "Flood fill";
3024 	    break;
3025       	  case GADGET_ID_GRAB_BRUSH:
3026 	    infotext = "Grabbing brush";
3027 	    break;
3028       	  case GADGET_ID_PICK_ELEMENT:
3029 	    infotext = "Picking element";
3030 	    break;
3031 
3032 	  default:
3033 	    infotext = "Drawing position";
3034 	    break;
3035 	}
3036 
3037 	if (drawing_function == GADGET_ID_PICK_ELEMENT)
3038 	  DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3039 		    "%s: %d, %d", infotext, lx, ly);
3040 	else
3041 	  DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3042 		    "%s: %d, %d", infotext,
3043 		    ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
3044       }
3045       else if (drawing_function == GADGET_ID_PICK_ELEMENT)
3046 	DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3047 		  "%s", getElementInfoText(Feld[lx][ly]));
3048       else
3049 	DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
3050 		  "Level position: %d, %d", lx, ly);
3051     }
3052 #endif
3053 
3054     /* misuse this function to draw brush cursor, if needed */
3055     if (edit_mode == ED_MODE_DRAWING && draw_with_brush && !button_status)
3056     {
3057       if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
3058 	CopyBrushToCursor(sx, sy);
3059       else
3060 	DeleteBrushFromCursor();
3061     }
3062   }
3063 }
3064