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