rnd-20070427-3-src
[rocksndiamonds.git] / src / init.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * init.c                                                   *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "init.h"
17 #include "events.h"
18 #include "screens.h"
19 #include "editor.h"
20 #include "game.h"
21 #include "tape.h"
22 #include "tools.h"
23 #include "files.h"
24 #include "network.h"
25 #include "netserv.h"
26 #include "cartoons.h"
27 #include "config.h"
28
29 #include "conf_e2g.c"   /* include auto-generated data structure definitions */
30 #include "conf_esg.c"   /* include auto-generated data structure definitions */
31 #include "conf_e2s.c"   /* include auto-generated data structure definitions */
32 #include "conf_fnt.c"   /* include auto-generated data structure definitions */
33 #include "conf_g2s.c"   /* include auto-generated data structure definitions */
34 #include "conf_g2m.c"   /* include auto-generated data structure definitions */
35 #include "conf_act.c"   /* include auto-generated data structure definitions */
36
37
38 #define CONFIG_TOKEN_FONT_INITIAL               "font.initial"
39 #define CONFIG_TOKEN_GLOBAL_BUSY                "global.busy"
40
41 #define DEBUG_PRINT_INIT_TIMESTAMPS             TRUE
42 #define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH       3
43
44
45 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
46 static struct GraphicInfo    anim_initial;
47
48 static int copy_properties[][5] =
49 {
50   {
51     EL_BUG,
52     EL_BUG_LEFT,                EL_BUG_RIGHT,
53     EL_BUG_UP,                  EL_BUG_DOWN
54   },
55   {
56     EL_SPACESHIP,
57     EL_SPACESHIP_LEFT,          EL_SPACESHIP_RIGHT,
58     EL_SPACESHIP_UP,            EL_SPACESHIP_DOWN
59   },
60   {
61     EL_BD_BUTTERFLY,
62     EL_BD_BUTTERFLY_LEFT,       EL_BD_BUTTERFLY_RIGHT,
63     EL_BD_BUTTERFLY_UP,         EL_BD_BUTTERFLY_DOWN
64   },
65   {
66     EL_BD_FIREFLY,
67     EL_BD_FIREFLY_LEFT,         EL_BD_FIREFLY_RIGHT,
68     EL_BD_FIREFLY_UP,           EL_BD_FIREFLY_DOWN
69   },
70   {
71     EL_PACMAN,
72     EL_PACMAN_LEFT,             EL_PACMAN_RIGHT,
73     EL_PACMAN_UP,               EL_PACMAN_DOWN
74   },
75   {
76     EL_YAMYAM,
77     EL_YAMYAM_LEFT,             EL_YAMYAM_RIGHT,
78     EL_YAMYAM_UP,               EL_YAMYAM_DOWN
79   },
80   {
81     EL_MOLE,
82     EL_MOLE_LEFT,               EL_MOLE_RIGHT,
83     EL_MOLE_UP,                 EL_MOLE_DOWN
84   },
85   {
86     -1,
87     -1, -1, -1, -1
88   }
89 };
90
91
92 static void print_init_timestamp(char *message)
93 {
94 #if DEBUG
95 #if DEBUG_PRINT_INIT_TIMESTAMPS
96   static char *last_message = NULL;
97   static int counter_nr = 0;
98   int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
99
100   if (strPrefix(message, "INIT"))
101   {
102     if (counter_nr + 1 < max_depth)
103     {
104       debug_print_timestamp(counter_nr, NULL);
105       debug_print_timestamp(counter_nr, message);
106     }
107
108     counter_nr++;
109
110     debug_print_timestamp(counter_nr, NULL);
111   }
112   else if (strPrefix(message, "DONE"))
113   {
114     counter_nr--;
115
116     if (counter_nr + 1 < max_depth ||
117         (counter_nr == 0 && max_depth == 1))
118     {
119       last_message = &message[4];
120
121       debug_print_timestamp(counter_nr, message);
122     }
123   }
124   else if (!strPrefix(message, "TIME") ||
125            !strSuffix(message, last_message))
126   {
127     if (counter_nr < max_depth)
128       debug_print_timestamp(counter_nr, message);
129   }
130 #endif
131 #endif
132 }
133
134 void DrawInitAnim()
135 {
136   struct GraphicInfo *graphic_info_last = graphic_info;
137   int graphic = 0;
138   static unsigned long action_delay = 0;
139   unsigned long action_delay_value = GameFrameDelay;
140   int sync_frame = FrameCounter;
141   int x, y;
142
143   if (anim_initial.bitmap == NULL || window == NULL)
144     return;
145
146   if (!DelayReached(&action_delay, action_delay_value))
147     return;
148
149 #if 0
150   {
151     static unsigned long last_counter = -1;
152     unsigned long current_counter = Counter();
153     unsigned long delay = current_counter - last_counter;
154
155     if (last_counter != -1 && delay > action_delay_value + 5)
156       printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
157
158     last_counter = current_counter;
159   }
160 #endif
161
162 #if 0
163   anim_initial.anim_mode = ANIM_LOOP;
164   anim_initial.anim_start_frame = 0;
165   anim_initial.offset_x = anim_initial.width;
166   anim_initial.offset_y = 0;
167 #endif
168
169 #if 1
170   x = ALIGNED_TEXT_XPOS(&init.busy);
171   y = ALIGNED_TEXT_YPOS(&init.busy);
172 #else
173   x = WIN_XSIZE / 2 - TILESIZE / 2;
174   y = WIN_YSIZE / 2 - TILESIZE / 2;
175 #endif
176
177 #if 0
178   {
179     static boolean done = FALSE;
180
181     if (!done)
182       printf("::: %d, %d, %d, %d => %d, %d\n",
183              init.busy.x, init.busy.y,
184              init.busy.align, init.busy.valign,
185              x, y);
186
187     done = TRUE;
188   }
189 #endif
190
191   graphic_info = &anim_initial;         /* graphic == 0 => anim_initial */
192
193   if (sync_frame % anim_initial.anim_delay == 0)
194     DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
195
196   graphic_info = graphic_info_last;
197
198   FrameCounter++;
199 }
200
201 void FreeGadgets()
202 {
203   FreeLevelEditorGadgets();
204   FreeGameButtons();
205   FreeTapeButtons();
206   FreeToolButtons();
207   FreeScreenGadgets();
208 }
209
210 void InitGadgets()
211 {
212   static boolean gadgets_initialized = FALSE;
213
214   if (gadgets_initialized)
215     FreeGadgets();
216
217   CreateLevelEditorGadgets();
218   CreateGameButtons();
219   CreateTapeButtons();
220   CreateToolButtons();
221   CreateScreenGadgets();
222
223   InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
224
225   gadgets_initialized = TRUE;
226 }
227
228 inline void InitElementSmallImagesScaledUp(int graphic)
229 {
230 #if 0
231   struct FileInfo *fi = getImageListEntryFromImageID(graphic);
232
233   printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
234 #endif
235
236   CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
237 }
238
239 void InitElementSmallImages()
240 {
241   static int special_graphics[] =
242   {
243     IMG_EDITOR_ELEMENT_BORDER,
244     IMG_EDITOR_ELEMENT_BORDER_INPUT,
245     IMG_EDITOR_CASCADE_LIST,
246     IMG_EDITOR_CASCADE_LIST_ACTIVE,
247     -1
248   };
249   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
250   int num_property_mappings = getImageListPropertyMappingSize();
251   int i;
252
253   /* initialize normal images from static configuration */
254   for (i = 0; element_to_graphic[i].element > -1; i++)
255     InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
256
257   /* initialize special images from static configuration */
258   for (i = 0; element_to_special_graphic[i].element > -1; i++)
259     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
260
261   /* initialize images from dynamic configuration (may be elements or other) */
262   for (i = 0; i < num_property_mappings; i++)
263     InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
264
265   /* initialize special images from above list (non-element images) */
266   for (i = 0; special_graphics[i] > -1; i++)
267     InitElementSmallImagesScaledUp(special_graphics[i]);
268 }
269
270 void InitScaledImages()
271 {
272   int i;
273
274   /* scale normal images from static configuration, if not already scaled */
275   for (i = 0; i < NUM_IMAGE_FILES; i++)
276     ScaleImage(i, graphic_info[i].scale_up_factor);
277 }
278
279 #if 1
280 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
281 void SetBitmaps_EM(Bitmap **em_bitmap)
282 {
283   em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
284   em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
285 }
286 #endif
287
288 static int getFontBitmapID(int font_nr)
289 {
290   int special = -1;
291
292   if (game_status >= GAME_MODE_TITLE_INITIAL &&
293       game_status <= GAME_MODE_PSEUDO_PREVIEW)
294     special = game_status;
295   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
296     special = GFX_SPECIAL_ARG_MAIN;
297 #if 0
298   else if (game_status == GAME_MODE_PLAYING)
299     special = GFX_SPECIAL_ARG_DOOR;
300 #endif
301
302   if (special != -1)
303     return font_info[font_nr].special_bitmap_id[special];
304   else
305     return font_nr;
306 }
307
308 static int getFontFromToken(char *token)
309 {
310 #if 1
311   char *value = getHashEntry(font_token_hash, token);
312
313   if (value != NULL)
314     return atoi(value);
315 #else
316   int i;
317
318   /* !!! OPTIMIZE THIS BY USING HASH !!! */
319   for (i = 0; i < NUM_FONTS; i++)
320     if (strEqual(token, font_info[i].token_name))
321       return i;
322 #endif
323
324   /* if font not found, use reliable default value */
325   return FONT_INITIAL_1;
326 }
327
328 void InitFontGraphicInfo()
329 {
330   static struct FontBitmapInfo *font_bitmap_info = NULL;
331   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
332   int num_property_mappings = getImageListPropertyMappingSize();
333   int num_font_bitmaps = NUM_FONTS;
334   int i, j;
335
336   if (graphic_info == NULL)             /* still at startup phase */
337   {
338     InitFontInfo(font_initial, NUM_INITIAL_FONTS,
339                  getFontBitmapID, getFontFromToken);
340
341     return;
342   }
343
344   /* ---------- initialize font graphic definitions ---------- */
345
346   /* always start with reliable default values (normal font graphics) */
347   for (i = 0; i < NUM_FONTS; i++)
348     font_info[i].graphic = IMG_FONT_INITIAL_1;
349
350   /* initialize normal font/graphic mapping from static configuration */
351   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
352   {
353     int font_nr = font_to_graphic[i].font_nr;
354     int special = font_to_graphic[i].special;
355     int graphic = font_to_graphic[i].graphic;
356
357     if (special != -1)
358       continue;
359
360     font_info[font_nr].graphic = graphic;
361   }
362
363   /* always start with reliable default values (special font graphics) */
364   for (i = 0; i < NUM_FONTS; i++)
365   {
366     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
367     {
368       font_info[i].special_graphic[j] = font_info[i].graphic;
369       font_info[i].special_bitmap_id[j] = i;
370     }
371   }
372
373   /* initialize special font/graphic mapping from static configuration */
374   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
375   {
376     int font_nr      = font_to_graphic[i].font_nr;
377     int special      = font_to_graphic[i].special;
378     int graphic      = font_to_graphic[i].graphic;
379     int base_graphic = font2baseimg(font_nr);
380
381     if (IS_SPECIAL_GFX_ARG(special))
382     {
383       boolean base_redefined =
384         getImageListEntryFromImageID(base_graphic)->redefined;
385       boolean special_redefined =
386         getImageListEntryFromImageID(graphic)->redefined;
387       boolean special_cloned = (graphic_info[graphic].clone_from != -1);
388
389       /* if the base font ("font.title_1", for example) has been redefined,
390          but not the special font ("font.title_1.LEVELS", for example), do not
391          use an existing (in this case considered obsolete) special font
392          anymore, but use the automatically determined default font */
393       /* special case: cloned special fonts must be explicitly redefined,
394          but are not automatically redefined by redefining base font */
395       if (base_redefined && !special_redefined && !special_cloned)
396         continue;
397
398       font_info[font_nr].special_graphic[special] = graphic;
399       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
400       num_font_bitmaps++;
401     }
402   }
403
404   /* initialize special font/graphic mapping from dynamic configuration */
405   for (i = 0; i < num_property_mappings; i++)
406   {
407     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
408     int special = property_mapping[i].ext3_index;
409     int graphic = property_mapping[i].artwork_index;
410
411     if (font_nr < 0)
412       continue;
413
414     if (IS_SPECIAL_GFX_ARG(special))
415     {
416       font_info[font_nr].special_graphic[special] = graphic;
417       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
418       num_font_bitmaps++;
419     }
420   }
421
422   /* correct special font/graphic mapping for cloned fonts for downwards
423      compatibility of PREVIEW fonts -- this is only needed for implicit
424      redefinition of special font by redefined base font, and only if other
425      fonts are cloned from this special font (like in the "Zelda" level set) */
426   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
427   {
428     int font_nr = font_to_graphic[i].font_nr;
429     int special = font_to_graphic[i].special;
430     int graphic = font_to_graphic[i].graphic;
431
432     if (IS_SPECIAL_GFX_ARG(special))
433     {
434       boolean special_redefined =
435         getImageListEntryFromImageID(graphic)->redefined;
436       boolean special_cloned = (graphic_info[graphic].clone_from != -1);
437
438       if (special_cloned && !special_redefined)
439       {
440         int j;
441
442         for (j = 0; font_to_graphic[j].font_nr > -1; j++)
443         {
444           int font_nr2 = font_to_graphic[j].font_nr;
445           int special2 = font_to_graphic[j].special;
446           int graphic2 = font_to_graphic[j].graphic;
447
448           if (IS_SPECIAL_GFX_ARG(special2) &&
449               graphic2 == graphic_info[graphic].clone_from)
450           {
451             font_info[font_nr].special_graphic[special] =
452               font_info[font_nr2].special_graphic[special2];
453             font_info[font_nr].special_bitmap_id[special] =
454               font_info[font_nr2].special_bitmap_id[special2];
455           }
456         }
457       }
458     }
459   }
460
461   /* reset non-redefined ".active" font graphics if normal font is redefined */
462   /* (this different treatment is needed because normal and active fonts are
463      independently defined ("active" is not a property of font definitions!) */
464   for (i = 0; i < NUM_FONTS; i++)
465   {
466     int font_nr_base = i;
467     int font_nr_active = FONT_ACTIVE(font_nr_base);
468
469     /* check only those fonts with exist as normal and ".active" variant */
470     if (font_nr_base != font_nr_active)
471     {
472       int base_graphic = font_info[font_nr_base].graphic;
473       int active_graphic = font_info[font_nr_active].graphic;
474       boolean base_redefined =
475         getImageListEntryFromImageID(base_graphic)->redefined;
476       boolean active_redefined =
477         getImageListEntryFromImageID(active_graphic)->redefined;
478
479       /* if the base font ("font.menu_1", for example) has been redefined,
480          but not the active font ("font.menu_1.active", for example), do not
481          use an existing (in this case considered obsolete) active font
482          anymore, but use the automatically determined default font */
483       if (base_redefined && !active_redefined)
484         font_info[font_nr_active].graphic = base_graphic;
485
486       /* now also check each "special" font (which may be the same as above) */
487       for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
488       {
489         int base_graphic = font_info[font_nr_base].special_graphic[j];
490         int active_graphic = font_info[font_nr_active].special_graphic[j];
491         boolean base_redefined =
492           getImageListEntryFromImageID(base_graphic)->redefined;
493         boolean active_redefined =
494           getImageListEntryFromImageID(active_graphic)->redefined;
495
496         /* same as above, but check special graphic definitions, for example:
497            redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
498         if (base_redefined && !active_redefined)
499         {
500           font_info[font_nr_active].special_graphic[j] =
501             font_info[font_nr_base].special_graphic[j];
502           font_info[font_nr_active].special_bitmap_id[j] =
503             font_info[font_nr_base].special_bitmap_id[j];
504         }
505       }
506     }
507   }
508
509   /* ---------- initialize font bitmap array ---------- */
510
511   if (font_bitmap_info != NULL)
512     FreeFontInfo(font_bitmap_info);
513
514   font_bitmap_info =
515     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
516
517   /* ---------- initialize font bitmap definitions ---------- */
518
519   for (i = 0; i < NUM_FONTS; i++)
520   {
521     if (i < NUM_INITIAL_FONTS)
522     {
523       font_bitmap_info[i] = font_initial[i];
524       continue;
525     }
526
527     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
528     {
529       int font_bitmap_id = font_info[i].special_bitmap_id[j];
530       int graphic = font_info[i].special_graphic[j];
531
532       /* set 'graphic_info' for font entries, if uninitialized (guessed) */
533       if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
534       {
535         graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
536         graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
537       }
538
539       /* copy font relevant information from graphics information */
540       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
541       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
542       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
543       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
544       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
545
546       font_bitmap_info[font_bitmap_id].draw_xoffset =
547         graphic_info[graphic].draw_xoffset;
548       font_bitmap_info[font_bitmap_id].draw_yoffset =
549         graphic_info[graphic].draw_yoffset;
550
551       font_bitmap_info[font_bitmap_id].num_chars =
552         graphic_info[graphic].anim_frames;
553       font_bitmap_info[font_bitmap_id].num_chars_per_line =
554         graphic_info[graphic].anim_frames_per_line;
555     }
556   }
557
558   InitFontInfo(font_bitmap_info, num_font_bitmaps,
559                getFontBitmapID, getFontFromToken);
560 }
561
562 void InitElementGraphicInfo()
563 {
564   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
565   int num_property_mappings = getImageListPropertyMappingSize();
566   int i, act, dir;
567
568   if (graphic_info == NULL)             /* still at startup phase */
569     return;
570
571   /* set values to -1 to identify later as "uninitialized" values */
572   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
573   {
574     for (act = 0; act < NUM_ACTIONS; act++)
575     {
576       element_info[i].graphic[act] = -1;
577       element_info[i].crumbled[act] = -1;
578
579       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
580       {
581         element_info[i].direction_graphic[act][dir] = -1;
582         element_info[i].direction_crumbled[act][dir] = -1;
583       }
584     }
585   }
586
587   UPDATE_BUSY_STATE();
588
589   /* initialize normal element/graphic mapping from static configuration */
590   for (i = 0; element_to_graphic[i].element > -1; i++)
591   {
592     int element      = element_to_graphic[i].element;
593     int action       = element_to_graphic[i].action;
594     int direction    = element_to_graphic[i].direction;
595     boolean crumbled = element_to_graphic[i].crumbled;
596     int graphic      = element_to_graphic[i].graphic;
597     int base_graphic = el2baseimg(element);
598
599     if (graphic_info[graphic].bitmap == NULL)
600       continue;
601
602     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
603         base_graphic != -1)
604     {
605       boolean base_redefined =
606         getImageListEntryFromImageID(base_graphic)->redefined;
607       boolean act_dir_redefined =
608         getImageListEntryFromImageID(graphic)->redefined;
609
610       /* if the base graphic ("emerald", for example) has been redefined,
611          but not the action graphic ("emerald.falling", for example), do not
612          use an existing (in this case considered obsolete) action graphic
613          anymore, but use the automatically determined default graphic */
614       if (base_redefined && !act_dir_redefined)
615         continue;
616     }
617
618     if (action < 0)
619       action = ACTION_DEFAULT;
620
621     if (crumbled)
622     {
623       if (direction > -1)
624         element_info[element].direction_crumbled[action][direction] = graphic;
625       else
626         element_info[element].crumbled[action] = graphic;
627     }
628     else
629     {
630       if (direction > -1)
631         element_info[element].direction_graphic[action][direction] = graphic;
632       else
633         element_info[element].graphic[action] = graphic;
634     }
635   }
636
637   /* initialize normal element/graphic mapping from dynamic configuration */
638   for (i = 0; i < num_property_mappings; i++)
639   {
640     int element   = property_mapping[i].base_index;
641     int action    = property_mapping[i].ext1_index;
642     int direction = property_mapping[i].ext2_index;
643     int special   = property_mapping[i].ext3_index;
644     int graphic   = property_mapping[i].artwork_index;
645     boolean crumbled = FALSE;
646
647 #if 0
648     if ((element == EL_EM_DYNAMITE ||
649          element == EL_EM_DYNAMITE_ACTIVE) &&
650         action == ACTION_ACTIVE &&
651         (special == GFX_SPECIAL_ARG_EDITOR ||
652          special == GFX_SPECIAL_ARG_PANEL))
653       printf("::: DYNAMIC: %d, %d, %d -> %d\n",
654              element, action, special, graphic);
655 #endif
656
657     if (special == GFX_SPECIAL_ARG_CRUMBLED)
658     {
659       special = -1;
660       crumbled = TRUE;
661     }
662
663     if (graphic_info[graphic].bitmap == NULL)
664       continue;
665
666     if (element >= MAX_NUM_ELEMENTS || special != -1)
667       continue;
668
669     if (action < 0)
670       action = ACTION_DEFAULT;
671
672     if (crumbled)
673     {
674       if (direction < 0)
675         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
676           element_info[element].direction_crumbled[action][dir] = -1;
677
678       if (direction > -1)
679         element_info[element].direction_crumbled[action][direction] = graphic;
680       else
681         element_info[element].crumbled[action] = graphic;
682     }
683     else
684     {
685       if (direction < 0)
686         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
687           element_info[element].direction_graphic[action][dir] = -1;
688
689       if (direction > -1)
690         element_info[element].direction_graphic[action][direction] = graphic;
691       else
692         element_info[element].graphic[action] = graphic;
693     }
694   }
695
696   /* now copy all graphics that are defined to be cloned from other graphics */
697   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
698   {
699     int graphic = element_info[i].graphic[ACTION_DEFAULT];
700     int crumbled_like, diggable_like;
701
702     if (graphic == -1)
703       continue;
704
705     crumbled_like = graphic_info[graphic].crumbled_like;
706     diggable_like = graphic_info[graphic].diggable_like;
707
708     if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
709     {
710       for (act = 0; act < NUM_ACTIONS; act++)
711         element_info[i].crumbled[act] =
712           element_info[crumbled_like].crumbled[act];
713       for (act = 0; act < NUM_ACTIONS; act++)
714         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
715           element_info[i].direction_crumbled[act][dir] =
716             element_info[crumbled_like].direction_crumbled[act][dir];
717     }
718
719     if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
720     {
721       element_info[i].graphic[ACTION_DIGGING] =
722         element_info[diggable_like].graphic[ACTION_DIGGING];
723       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
724         element_info[i].direction_graphic[ACTION_DIGGING][dir] =
725           element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
726     }
727   }
728
729 #if 1
730   /* set hardcoded definitions for some runtime elements without graphic */
731   element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
732 #endif
733
734 #if 1
735   /* set hardcoded definitions for some internal elements without graphic */
736   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
737   {
738     if (IS_EDITOR_CASCADE_INACTIVE(i))
739       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
740     else if (IS_EDITOR_CASCADE_ACTIVE(i))
741       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
742   }
743 #endif
744
745   /* now set all undefined/invalid graphics to -1 to set to default after it */
746   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
747   {
748     for (act = 0; act < NUM_ACTIONS; act++)
749     {
750       int graphic;
751
752       graphic = element_info[i].graphic[act];
753       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
754         element_info[i].graphic[act] = -1;
755
756       graphic = element_info[i].crumbled[act];
757       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
758         element_info[i].crumbled[act] = -1;
759
760       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
761       {
762         graphic = element_info[i].direction_graphic[act][dir];
763         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
764           element_info[i].direction_graphic[act][dir] = -1;
765
766         graphic = element_info[i].direction_crumbled[act][dir];
767         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
768           element_info[i].direction_crumbled[act][dir] = -1;
769       }
770     }
771   }
772
773   UPDATE_BUSY_STATE();
774
775   /* adjust graphics with 2nd tile for movement according to direction
776      (do this before correcting '-1' values to minimize calculations) */
777   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
778   {
779     for (act = 0; act < NUM_ACTIONS; act++)
780     {
781       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
782       {
783         int graphic = element_info[i].direction_graphic[act][dir];
784         int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
785
786         if (act == ACTION_FALLING)      /* special case */
787           graphic = element_info[i].graphic[act];
788
789         if (graphic != -1 &&
790             graphic_info[graphic].double_movement &&
791             graphic_info[graphic].swap_double_tiles != 0)
792         {
793           struct GraphicInfo *g = &graphic_info[graphic];
794           int src_x_front = g->src_x;
795           int src_y_front = g->src_y;
796           int src_x_back = g->src_x + g->offset2_x;
797           int src_y_back = g->src_y + g->offset2_y;
798           boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
799                                                    g->offset_y != 0);
800           boolean front_is_left_or_upper = (src_x_front < src_x_back ||
801                                             src_y_front < src_y_back);
802           boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
803           boolean swap_movement_tiles_autodetected =
804             (!frames_are_ordered_diagonally &&
805              ((move_dir == MV_BIT_LEFT  && !front_is_left_or_upper) ||
806               (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
807               (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
808               (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
809           Bitmap *dummy;
810
811           /* swap frontside and backside graphic tile coordinates, if needed */
812           if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
813           {
814             /* get current (wrong) backside tile coordinates */
815             getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
816                                 TRUE);
817
818             /* set frontside tile coordinates to backside tile coordinates */
819             g->src_x = src_x_back;
820             g->src_y = src_y_back;
821
822             /* invert tile offset to point to new backside tile coordinates */
823             g->offset2_x *= -1;
824             g->offset2_y *= -1;
825
826             /* do not swap front and backside tiles again after correction */
827             g->swap_double_tiles = 0;
828           }
829         }
830       }
831     }
832   }
833
834   UPDATE_BUSY_STATE();
835
836   /* now set all '-1' values to element specific default values */
837   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
838   {
839     int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
840     int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
841     int default_direction_graphic[NUM_DIRECTIONS_FULL];
842     int default_direction_crumbled[NUM_DIRECTIONS_FULL];
843
844     if (default_graphic == -1)
845       default_graphic = IMG_UNKNOWN;
846 #if 1
847     if (default_crumbled == -1)
848       default_crumbled = default_graphic;
849 #else
850     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
851     if (default_crumbled == -1)
852       default_crumbled = IMG_EMPTY;
853 #endif
854
855     for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
856     {
857       default_direction_graphic[dir] =
858         element_info[i].direction_graphic[ACTION_DEFAULT][dir];
859       default_direction_crumbled[dir] =
860         element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
861
862       if (default_direction_graphic[dir] == -1)
863         default_direction_graphic[dir] = default_graphic;
864 #if 1
865       if (default_direction_crumbled[dir] == -1)
866         default_direction_crumbled[dir] = default_direction_graphic[dir];
867 #else
868       /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
869       if (default_direction_crumbled[dir] == -1)
870         default_direction_crumbled[dir] = default_crumbled;
871 #endif
872     }
873
874     for (act = 0; act < NUM_ACTIONS; act++)
875     {
876       boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
877                             (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
878                             (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
879       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
880                              act == ACTION_TURNING_FROM_RIGHT ||
881                              act == ACTION_TURNING_FROM_UP ||
882                              act == ACTION_TURNING_FROM_DOWN);
883
884       /* generic default action graphic (defined by "[default]" directive) */
885       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
886       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
887       int default_remove_graphic = IMG_EMPTY;
888
889       if (act_remove && default_action_graphic != -1)
890         default_remove_graphic = default_action_graphic;
891
892       /* look for special default action graphic (classic game specific) */
893       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
894         default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
895       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
896         default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
897       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
898         default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
899
900       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
901         default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
902       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
903         default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
904       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
905         default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
906
907 #if 1
908       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
909       /* !!! make this better !!! */
910       if (i == EL_EMPTY_SPACE)
911       {
912         default_action_graphic = element_info[EL_DEFAULT].graphic[act];
913         default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
914       }
915 #endif
916
917       if (default_action_graphic == -1)
918         default_action_graphic = default_graphic;
919 #if 1
920       if (default_action_crumbled == -1)
921         default_action_crumbled = default_action_graphic;
922 #else
923       /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
924       if (default_action_crumbled == -1)
925         default_action_crumbled = default_crumbled;
926 #endif
927
928       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
929       {
930         /* use action graphic as the default direction graphic, if undefined */
931         int default_action_direction_graphic = element_info[i].graphic[act];
932         int default_action_direction_crumbled = element_info[i].crumbled[act];
933
934         /* no graphic for current action -- use default direction graphic */
935         if (default_action_direction_graphic == -1)
936           default_action_direction_graphic =
937             (act_remove ? default_remove_graphic :
938              act_turning ?
939              element_info[i].direction_graphic[ACTION_TURNING][dir] :
940              default_action_graphic != default_graphic ?
941              default_action_graphic :
942              default_direction_graphic[dir]);
943
944         if (element_info[i].direction_graphic[act][dir] == -1)
945           element_info[i].direction_graphic[act][dir] =
946             default_action_direction_graphic;
947
948 #if 1
949         if (default_action_direction_crumbled == -1)
950           default_action_direction_crumbled =
951             element_info[i].direction_graphic[act][dir];
952 #else
953         if (default_action_direction_crumbled == -1)
954           default_action_direction_crumbled =
955             (act_remove ? default_remove_graphic :
956              act_turning ?
957              element_info[i].direction_crumbled[ACTION_TURNING][dir] :
958              default_action_crumbled != default_crumbled ?
959              default_action_crumbled :
960              default_direction_crumbled[dir]);
961 #endif
962
963         if (element_info[i].direction_crumbled[act][dir] == -1)
964           element_info[i].direction_crumbled[act][dir] =
965             default_action_direction_crumbled;
966       }
967
968       /* no graphic for this specific action -- use default action graphic */
969       if (element_info[i].graphic[act] == -1)
970         element_info[i].graphic[act] =
971           (act_remove ? default_remove_graphic :
972            act_turning ? element_info[i].graphic[ACTION_TURNING] :
973            default_action_graphic);
974 #if 1
975       if (element_info[i].crumbled[act] == -1)
976         element_info[i].crumbled[act] = element_info[i].graphic[act];
977 #else
978       if (element_info[i].crumbled[act] == -1)
979         element_info[i].crumbled[act] =
980           (act_remove ? default_remove_graphic :
981            act_turning ? element_info[i].crumbled[ACTION_TURNING] :
982            default_action_crumbled);
983 #endif
984     }
985   }
986
987   UPDATE_BUSY_STATE();
988
989 #if 0
990   /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
991   /* set animation mode to "none" for each graphic with only 1 frame */
992   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
993   {
994     for (act = 0; act < NUM_ACTIONS; act++)
995     {
996       int graphic = element_info[i].graphic[act];
997       int crumbled = element_info[i].crumbled[act];
998
999       if (graphic_info[graphic].anim_frames == 1)
1000         graphic_info[graphic].anim_mode = ANIM_NONE;
1001       if (graphic_info[crumbled].anim_frames == 1)
1002         graphic_info[crumbled].anim_mode = ANIM_NONE;
1003
1004       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1005       {
1006         graphic = element_info[i].direction_graphic[act][dir];
1007         crumbled = element_info[i].direction_crumbled[act][dir];
1008
1009         if (graphic_info[graphic].anim_frames == 1)
1010           graphic_info[graphic].anim_mode = ANIM_NONE;
1011         if (graphic_info[crumbled].anim_frames == 1)
1012           graphic_info[crumbled].anim_mode = ANIM_NONE;
1013       }
1014     }
1015   }
1016 #endif
1017
1018 #if 0
1019 #if DEBUG
1020   if (options.verbose)
1021   {
1022     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1023       if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
1024           i != EL_UNKNOWN)
1025         Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
1026               element_info[i].token_name, i);
1027   }
1028 #endif
1029 #endif
1030 }
1031
1032 void InitElementSpecialGraphicInfo()
1033 {
1034   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1035   int num_property_mappings = getImageListPropertyMappingSize();
1036   int i, j;
1037
1038   /* always start with reliable default values */
1039   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1040     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1041       element_info[i].special_graphic[j] =
1042         element_info[i].graphic[ACTION_DEFAULT];
1043
1044   /* initialize special element/graphic mapping from static configuration */
1045   for (i = 0; element_to_special_graphic[i].element > -1; i++)
1046   {
1047     int element = element_to_special_graphic[i].element;
1048     int special = element_to_special_graphic[i].special;
1049     int graphic = element_to_special_graphic[i].graphic;
1050     int base_graphic = el2baseimg(element);
1051     boolean base_redefined =
1052       getImageListEntryFromImageID(base_graphic)->redefined;
1053     boolean special_redefined =
1054       getImageListEntryFromImageID(graphic)->redefined;
1055
1056 #if 0
1057     if ((element == EL_EM_DYNAMITE ||
1058          element == EL_EM_DYNAMITE_ACTIVE) &&
1059         (special == GFX_SPECIAL_ARG_EDITOR ||
1060          special == GFX_SPECIAL_ARG_PANEL))
1061       printf("::: SPECIAL STATIC: %d, %d -> %d\n",
1062              element, special, graphic);
1063 #endif
1064
1065     /* if the base graphic ("emerald", for example) has been redefined,
1066        but not the special graphic ("emerald.EDITOR", for example), do not
1067        use an existing (in this case considered obsolete) special graphic
1068        anymore, but use the automatically created (down-scaled) graphic */
1069     if (base_redefined && !special_redefined)
1070       continue;
1071
1072     element_info[element].special_graphic[special] = graphic;
1073   }
1074
1075   /* initialize special element/graphic mapping from dynamic configuration */
1076   for (i = 0; i < num_property_mappings; i++)
1077   {
1078     int element   = property_mapping[i].base_index;
1079     int action    = property_mapping[i].ext1_index;
1080     int direction = property_mapping[i].ext2_index;
1081     int special   = property_mapping[i].ext3_index;
1082     int graphic   = property_mapping[i].artwork_index;
1083
1084 #if 0
1085     if ((element == EL_EM_DYNAMITE ||
1086          element == EL_EM_DYNAMITE_ACTIVE ||
1087          element == EL_CONVEYOR_BELT_1_MIDDLE ||
1088          element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
1089         (special == GFX_SPECIAL_ARG_EDITOR ||
1090          special == GFX_SPECIAL_ARG_PANEL))
1091       printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
1092              element, special, graphic, property_mapping[i].ext1_index);
1093 #endif
1094
1095 #if 0
1096     if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
1097         action == ACTION_ACTIVE)
1098     {
1099       element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
1100       action = -1;
1101     }
1102 #endif
1103
1104 #if 0
1105     if (element == EL_MAGIC_WALL &&
1106         action == ACTION_ACTIVE)
1107     {
1108       element = EL_MAGIC_WALL_ACTIVE;
1109       action = -1;
1110     }
1111 #endif
1112
1113 #if 1
1114     /* for action ".active", replace element with active element, if exists */
1115     if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1116     {
1117       element = ELEMENT_ACTIVE(element);
1118       action = -1;
1119     }
1120 #endif
1121
1122     if (element >= MAX_NUM_ELEMENTS)
1123       continue;
1124
1125     /* do not change special graphic if action or direction was specified */
1126     if (action != -1 || direction != -1)
1127       continue;
1128
1129     if (IS_SPECIAL_GFX_ARG(special))
1130       element_info[element].special_graphic[special] = graphic;
1131   }
1132
1133   /* now set all undefined/invalid graphics to default */
1134   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1135     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1136       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1137         element_info[i].special_graphic[j] =
1138           element_info[i].graphic[ACTION_DEFAULT];
1139 }
1140
1141 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1142 {
1143   if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1144     return get_parameter_value(value_raw, suffix, type);
1145
1146   if (strEqual(value_raw, ARG_UNDEFINED))
1147     return ARG_UNDEFINED_VALUE;
1148
1149 #if 1
1150   if (type == TYPE_ELEMENT)
1151   {
1152     char *value = getHashEntry(element_token_hash, value_raw);
1153
1154     return (value != NULL ? atoi(value) : EL_UNDEFINED);
1155   }
1156   else if (type == TYPE_GRAPHIC)
1157   {
1158     char *value = getHashEntry(graphic_token_hash, value_raw);
1159
1160     return (value != NULL ? atoi(value) : IMG_UNDEFINED);
1161   }
1162
1163 #else
1164
1165   int i;
1166   int x = 0;
1167
1168   /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
1169   /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
1170
1171   /* !!! OPTIMIZE THIS BY USING HASH !!! */
1172   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1173     if (strEqual(element_info[i].token_name, value_raw))
1174       return i;
1175
1176   /* !!! OPTIMIZE THIS BY USING HASH !!! */
1177   for (i = 0; image_config[i].token != NULL; i++)
1178   {
1179     int len_config_value = strlen(image_config[i].value);
1180
1181     if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
1182         !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
1183         !strEqual(image_config[i].value, UNDEFINED_FILENAME))
1184       continue;
1185
1186     if (strEqual(image_config[i].token, value_raw))
1187       return x;
1188
1189     x++;
1190   }
1191 #endif
1192
1193   return -1;
1194 }
1195
1196 static int get_scaled_graphic_width(int graphic)
1197 {
1198   int original_width = getOriginalImageWidthFromImageID(graphic);
1199   int scale_up_factor = graphic_info[graphic].scale_up_factor;
1200
1201   return original_width * scale_up_factor;
1202 }
1203
1204 static int get_scaled_graphic_height(int graphic)
1205 {
1206   int original_height = getOriginalImageHeightFromImageID(graphic);
1207   int scale_up_factor = graphic_info[graphic].scale_up_factor;
1208
1209   return original_height * scale_up_factor;
1210 }
1211
1212 static void set_graphic_parameters_ext(int graphic, struct GraphicInfo *g,
1213                                        int *parameter, Bitmap *src_bitmap)
1214 {
1215   int anim_frames_per_row = 1, anim_frames_per_col = 1;
1216   int anim_frames_per_line = 1;
1217
1218   /* always start with reliable default values */
1219   g->src_image_width = 0;
1220   g->src_image_height = 0;
1221   g->src_x = 0;
1222   g->src_y = 0;
1223   g->width  = TILEX;                    /* default for element graphics */
1224   g->height = TILEY;                    /* default for element graphics */
1225   g->offset_x = 0;                      /* one or both of these values ... */
1226   g->offset_y = 0;                      /* ... will be corrected later */
1227   g->offset2_x = 0;                     /* one or both of these values ... */
1228   g->offset2_y = 0;                     /* ... will be corrected later */
1229   g->swap_double_tiles = -1;            /* auto-detect tile swapping */
1230   g->crumbled_like = -1;                /* do not use clone element */
1231   g->diggable_like = -1;                /* do not use clone element */
1232   g->border_size = TILEX / 8;           /* "CRUMBLED" border size */
1233   g->scale_up_factor = 1;               /* default: no scaling up */
1234   g->clone_from = -1;                   /* do not use clone graphic */
1235   g->anim_delay_fixed = 0;
1236   g->anim_delay_random = 0;
1237   g->post_delay_fixed = 0;
1238   g->post_delay_random = 0;
1239   g->fade_mode = FADE_MODE_DEFAULT;
1240   g->fade_delay = -1;
1241   g->post_delay = -1;
1242   g->auto_delay = -1;
1243   g->align = ALIGN_CENTER;              /* default for title screens */
1244   g->valign = VALIGN_MIDDLE;            /* default for title screens */
1245   g->sort_priority = 0;                 /* default for title screens */
1246
1247   g->bitmap = src_bitmap;
1248
1249 #if 1
1250   /* optional zoom factor for scaling up the image to a larger size */
1251   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1252     g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1253   if (g->scale_up_factor < 1)
1254     g->scale_up_factor = 1;             /* no scaling */
1255 #endif
1256
1257 #if 1
1258   if (g->use_image_size)
1259   {
1260     /* set new default bitmap size (with scaling, but without small images) */
1261     g->width  = get_scaled_graphic_width(graphic);
1262     g->height = get_scaled_graphic_height(graphic);
1263   }
1264 #endif
1265
1266   /* optional x and y tile position of animation frame sequence */
1267   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1268     g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
1269   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1270     g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
1271
1272   /* optional x and y pixel position of animation frame sequence */
1273   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1274     g->src_x = parameter[GFX_ARG_X];
1275   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1276     g->src_y = parameter[GFX_ARG_Y];
1277
1278   /* optional width and height of each animation frame */
1279   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1280     g->width = parameter[GFX_ARG_WIDTH];
1281   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1282     g->height = parameter[GFX_ARG_HEIGHT];
1283
1284 #if 0
1285   /* optional zoom factor for scaling up the image to a larger size */
1286   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1287     g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1288   if (g->scale_up_factor < 1)
1289     g->scale_up_factor = 1;             /* no scaling */
1290 #endif
1291
1292   if (src_bitmap)
1293   {
1294     /* get final bitmap size (with scaling, but without small images) */
1295     int src_image_width  = get_scaled_graphic_width(graphic);
1296     int src_image_height = get_scaled_graphic_height(graphic);
1297
1298     anim_frames_per_row = src_image_width  / g->width;
1299     anim_frames_per_col = src_image_height / g->height;
1300
1301     g->src_image_width  = src_image_width;
1302     g->src_image_height = src_image_height;
1303   }
1304
1305   /* correct x or y offset dependent of vertical or horizontal frame order */
1306   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
1307   {
1308     g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1309                    parameter[GFX_ARG_OFFSET] : g->height);
1310     anim_frames_per_line = anim_frames_per_col;
1311   }
1312   else                                  /* frames are ordered horizontally */
1313   {
1314     g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1315                    parameter[GFX_ARG_OFFSET] : g->width);
1316     anim_frames_per_line = anim_frames_per_row;
1317   }
1318
1319   /* optionally, the x and y offset of frames can be specified directly */
1320   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1321     g->offset_x = parameter[GFX_ARG_XOFFSET];
1322   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1323     g->offset_y = parameter[GFX_ARG_YOFFSET];
1324
1325   /* optionally, moving animations may have separate start and end graphics */
1326   g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1327
1328   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1329     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1330
1331   /* correct x or y offset2 dependent of vertical or horizontal frame order */
1332   if (parameter[GFX_ARG_2ND_VERTICAL])  /* frames are ordered vertically */
1333     g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1334                     parameter[GFX_ARG_2ND_OFFSET] : g->height);
1335   else                                  /* frames are ordered horizontally */
1336     g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1337                     parameter[GFX_ARG_2ND_OFFSET] : g->width);
1338
1339   /* optionally, the x and y offset of 2nd graphic can be specified directly */
1340   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1341     g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1342   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1343     g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1344
1345   /* optionally, the second movement tile can be specified as start tile */
1346   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1347     g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1348
1349   /* automatically determine correct number of frames, if not defined */
1350   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1351     g->anim_frames = parameter[GFX_ARG_FRAMES];
1352   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1353     g->anim_frames = anim_frames_per_row;
1354   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1355     g->anim_frames = anim_frames_per_col;
1356   else
1357     g->anim_frames = 1;
1358
1359   if (g->anim_frames == 0)              /* frames must be at least 1 */
1360     g->anim_frames = 1;
1361
1362   g->anim_frames_per_line =
1363     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1364      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1365
1366   g->anim_delay = parameter[GFX_ARG_DELAY];
1367   if (g->anim_delay == 0)               /* delay must be at least 1 */
1368     g->anim_delay = 1;
1369
1370   g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1371 #if 0
1372   if (g->anim_frames == 1)
1373     g->anim_mode = ANIM_NONE;
1374 #endif
1375
1376   /* automatically determine correct start frame, if not defined */
1377   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1378     g->anim_start_frame = 0;
1379   else if (g->anim_mode & ANIM_REVERSE)
1380     g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1381   else
1382     g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1383
1384   /* animation synchronized with global frame counter, not move position */
1385   g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1386
1387   /* optional element for cloning crumble graphics */
1388   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1389     g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1390
1391   /* optional element for cloning digging graphics */
1392   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1393     g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1394
1395   /* optional border size for "crumbling" diggable graphics */
1396   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1397     g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1398
1399   /* this is only used for player "boring" and "sleeping" actions */
1400   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1401     g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1402   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1403     g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1404   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1405     g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1406   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1407     g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1408
1409   /* this is only used for toon animations */
1410   g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
1411   g->step_delay  = parameter[GFX_ARG_STEP_DELAY];
1412
1413   /* this is only used for drawing font characters */
1414   g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1415   g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1416
1417   /* this is only used for drawing envelope graphics */
1418   g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1419
1420   /* optional graphic for cloning all graphics settings */
1421   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1422     g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1423
1424   /* optional settings for drawing title screens and title messages */
1425   if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1426     g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1427   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1428     g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1429   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1430     g->post_delay = parameter[GFX_ARG_POST_DELAY];
1431   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1432     g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1433   if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1434     g->align = parameter[GFX_ARG_ALIGN];
1435   if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1436     g->valign = parameter[GFX_ARG_VALIGN];
1437   if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1438     g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1439 }
1440
1441 static void set_graphic_parameters(int graphic)
1442 {
1443 #if 1
1444   struct FileInfo *image = getImageListEntryFromImageID(graphic);
1445   char **parameter_raw = image->parameter;
1446   Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1447   int parameter[NUM_GFX_ARGS];
1448   int i;
1449
1450   /* if fallback to default artwork is done, also use the default parameters */
1451   if (image->fallback_to_default)
1452     parameter_raw = image->default_parameter;
1453
1454   /* get integer values from string parameters */
1455   for (i = 0; i < NUM_GFX_ARGS; i++)
1456     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1457                                                image_config_suffix[i].token,
1458                                                image_config_suffix[i].type);
1459
1460   set_graphic_parameters_ext(graphic, &graphic_info[graphic],
1461                              parameter, src_bitmap);
1462
1463 #else
1464
1465   struct FileInfo *image = getImageListEntryFromImageID(graphic);
1466   char **parameter_raw = image->parameter;
1467   Bitmap *src_bitmap = getBitmapFromImageID(graphic);
1468   int parameter[NUM_GFX_ARGS];
1469   int anim_frames_per_row = 1, anim_frames_per_col = 1;
1470   int anim_frames_per_line = 1;
1471   int i;
1472
1473   /* if fallback to default artwork is done, also use the default parameters */
1474   if (image->fallback_to_default)
1475     parameter_raw = image->default_parameter;
1476
1477   /* get integer values from string parameters */
1478   for (i = 0; i < NUM_GFX_ARGS; i++)
1479     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1480                                                image_config_suffix[i].token,
1481                                                image_config_suffix[i].type);
1482
1483   graphic_info[graphic].bitmap = src_bitmap;
1484
1485   /* always start with reliable default values */
1486   graphic_info[graphic].src_image_width = 0;
1487   graphic_info[graphic].src_image_height = 0;
1488   graphic_info[graphic].src_x = 0;
1489   graphic_info[graphic].src_y = 0;
1490   graphic_info[graphic].width  = TILEX; /* default for element graphics */
1491   graphic_info[graphic].height = TILEY; /* default for element graphics */
1492   graphic_info[graphic].offset_x = 0;   /* one or both of these values ... */
1493   graphic_info[graphic].offset_y = 0;   /* ... will be corrected later */
1494   graphic_info[graphic].offset2_x = 0;  /* one or both of these values ... */
1495   graphic_info[graphic].offset2_y = 0;  /* ... will be corrected later */
1496   graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
1497   graphic_info[graphic].crumbled_like = -1;     /* do not use clone element */
1498   graphic_info[graphic].diggable_like = -1;     /* do not use clone element */
1499   graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
1500   graphic_info[graphic].scale_up_factor = 1;    /* default: no scaling up */
1501   graphic_info[graphic].clone_from = -1;        /* do not use clone graphic */
1502   graphic_info[graphic].anim_delay_fixed = 0;
1503   graphic_info[graphic].anim_delay_random = 0;
1504   graphic_info[graphic].post_delay_fixed = 0;
1505   graphic_info[graphic].post_delay_random = 0;
1506   graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
1507   graphic_info[graphic].fade_delay = -1;
1508   graphic_info[graphic].post_delay = -1;
1509   graphic_info[graphic].auto_delay = -1;
1510   graphic_info[graphic].align = ALIGN_CENTER;   /* default for title screens */
1511   graphic_info[graphic].valign = VALIGN_MIDDLE; /* default for title screens */
1512   graphic_info[graphic].sort_priority = 0;      /* default for title screens */
1513
1514 #if 1
1515   /* optional zoom factor for scaling up the image to a larger size */
1516   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1517     graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1518   if (graphic_info[graphic].scale_up_factor < 1)
1519     graphic_info[graphic].scale_up_factor = 1;          /* no scaling */
1520 #endif
1521
1522 #if 1
1523   if (graphic_info[graphic].use_image_size)
1524   {
1525     /* set new default bitmap size (with scaling, but without small images) */
1526     graphic_info[graphic].width  = get_scaled_graphic_width(graphic);
1527     graphic_info[graphic].height = get_scaled_graphic_height(graphic);
1528   }
1529 #endif
1530
1531   /* optional x and y tile position of animation frame sequence */
1532   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1533     graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
1534   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1535     graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
1536
1537   /* optional x and y pixel position of animation frame sequence */
1538   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1539     graphic_info[graphic].src_x = parameter[GFX_ARG_X];
1540   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1541     graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
1542
1543   /* optional width and height of each animation frame */
1544   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1545     graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1546   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1547     graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1548
1549 #if 0
1550   /* optional zoom factor for scaling up the image to a larger size */
1551   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1552     graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1553   if (graphic_info[graphic].scale_up_factor < 1)
1554     graphic_info[graphic].scale_up_factor = 1;          /* no scaling */
1555 #endif
1556
1557   if (src_bitmap)
1558   {
1559     /* get final bitmap size (with scaling, but without small images) */
1560     int src_image_width  = get_scaled_graphic_width(graphic);
1561     int src_image_height = get_scaled_graphic_height(graphic);
1562
1563     anim_frames_per_row = src_image_width  / graphic_info[graphic].width;
1564     anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1565
1566     graphic_info[graphic].src_image_width  = src_image_width;
1567     graphic_info[graphic].src_image_height = src_image_height;
1568   }
1569
1570   /* correct x or y offset dependent of vertical or horizontal frame order */
1571   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
1572   {
1573     graphic_info[graphic].offset_y =
1574       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1575        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1576     anim_frames_per_line = anim_frames_per_col;
1577   }
1578   else                                  /* frames are ordered horizontally */
1579   {
1580     graphic_info[graphic].offset_x =
1581       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1582        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1583     anim_frames_per_line = anim_frames_per_row;
1584   }
1585
1586   /* optionally, the x and y offset of frames can be specified directly */
1587   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1588     graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1589   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1590     graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1591
1592   /* optionally, moving animations may have separate start and end graphics */
1593   graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1594
1595   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1596     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1597
1598   /* correct x or y offset2 dependent of vertical or horizontal frame order */
1599   if (parameter[GFX_ARG_2ND_VERTICAL])  /* frames are ordered vertically */
1600     graphic_info[graphic].offset2_y =
1601       (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1602        parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1603   else                                  /* frames are ordered horizontally */
1604     graphic_info[graphic].offset2_x =
1605       (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1606        parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1607
1608   /* optionally, the x and y offset of 2nd graphic can be specified directly */
1609   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1610     graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1611   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1612     graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1613
1614   /* optionally, the second movement tile can be specified as start tile */
1615   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1616     graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1617
1618   /* automatically determine correct number of frames, if not defined */
1619   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1620     graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1621   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1622     graphic_info[graphic].anim_frames = anim_frames_per_row;
1623   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1624     graphic_info[graphic].anim_frames = anim_frames_per_col;
1625   else
1626     graphic_info[graphic].anim_frames = 1;
1627
1628   if (graphic_info[graphic].anim_frames == 0)   /* frames must be at least 1 */
1629     graphic_info[graphic].anim_frames = 1;
1630
1631   graphic_info[graphic].anim_frames_per_line =
1632     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1633      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1634
1635   graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1636   if (graphic_info[graphic].anim_delay == 0)    /* delay must be at least 1 */
1637     graphic_info[graphic].anim_delay = 1;
1638
1639   graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1640 #if 0
1641   if (graphic_info[graphic].anim_frames == 1)
1642     graphic_info[graphic].anim_mode = ANIM_NONE;
1643 #endif
1644
1645   /* automatically determine correct start frame, if not defined */
1646   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1647     graphic_info[graphic].anim_start_frame = 0;
1648   else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1649     graphic_info[graphic].anim_start_frame =
1650       graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1651   else
1652     graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1653
1654   /* animation synchronized with global frame counter, not move position */
1655   graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1656
1657   /* optional element for cloning crumble graphics */
1658   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1659     graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1660
1661   /* optional element for cloning digging graphics */
1662   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1663     graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1664
1665   /* optional border size for "crumbling" diggable graphics */
1666   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1667     graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1668
1669   /* this is only used for player "boring" and "sleeping" actions */
1670   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1671     graphic_info[graphic].anim_delay_fixed =
1672       parameter[GFX_ARG_ANIM_DELAY_FIXED];
1673   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1674     graphic_info[graphic].anim_delay_random =
1675       parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1676   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1677     graphic_info[graphic].post_delay_fixed =
1678       parameter[GFX_ARG_POST_DELAY_FIXED];
1679   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1680     graphic_info[graphic].post_delay_random =
1681       parameter[GFX_ARG_POST_DELAY_RANDOM];
1682
1683   /* this is only used for toon animations */
1684   graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1685   graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
1686
1687   /* this is only used for drawing font characters */
1688   graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1689   graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1690
1691   /* this is only used for drawing envelope graphics */
1692   graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1693
1694   /* optional graphic for cloning all graphics settings */
1695   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1696     graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1697
1698   /* optional settings for drawing title screens and title messages */
1699   if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1700     graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
1701   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1702     graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1703   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1704     graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1705   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1706     graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1707   if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1708     graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
1709   if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1710     graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
1711   if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1712     graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1713 #endif
1714
1715   UPDATE_BUSY_STATE();
1716 }
1717
1718 static void set_cloned_graphic_parameters(int graphic)
1719 {
1720   int fallback_graphic = IMG_CHAR_EXCLAM;
1721   int max_num_images = getImageListSize();
1722   int clone_graphic = graphic_info[graphic].clone_from;
1723   int num_references_followed = 1;
1724
1725   while (graphic_info[clone_graphic].clone_from != -1 &&
1726          num_references_followed < max_num_images)
1727   {
1728     clone_graphic = graphic_info[clone_graphic].clone_from;
1729
1730     num_references_followed++;
1731   }
1732
1733   if (num_references_followed >= max_num_images)
1734   {
1735     Error(ERR_INFO_LINE, "-");
1736     Error(ERR_INFO, "warning: error found in config file:");
1737     Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1738     Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1739     Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1740     Error(ERR_INFO, "custom graphic rejected for this element/action");
1741
1742     if (graphic == fallback_graphic)
1743       Error(ERR_EXIT, "fatal error: no fallback graphic available");
1744
1745     Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1746     Error(ERR_INFO_LINE, "-");
1747
1748     graphic_info[graphic] = graphic_info[fallback_graphic];
1749   }
1750   else
1751   {
1752     graphic_info[graphic] = graphic_info[clone_graphic];
1753     graphic_info[graphic].clone_from = clone_graphic;
1754   }
1755 }
1756
1757 static void InitGraphicInfo()
1758 {
1759   int fallback_graphic = IMG_CHAR_EXCLAM;
1760   int num_images = getImageListSize();
1761   int i;
1762
1763 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1764   static boolean clipmasks_initialized = FALSE;
1765   Pixmap src_pixmap;
1766   XGCValues clip_gc_values;
1767   unsigned long clip_gc_valuemask;
1768   GC copy_clipmask_gc = None;
1769 #endif
1770
1771   /* use image size as default values for width and height for these images */
1772   static int full_size_graphics[] =
1773   {
1774     IMG_GLOBAL_BORDER,
1775     IMG_GLOBAL_DOOR,
1776
1777     IMG_BACKGROUND_ENVELOPE_1,
1778     IMG_BACKGROUND_ENVELOPE_2,
1779     IMG_BACKGROUND_ENVELOPE_3,
1780     IMG_BACKGROUND_ENVELOPE_4,
1781
1782     IMG_BACKGROUND,
1783     IMG_BACKGROUND_TITLE_INITIAL,
1784     IMG_BACKGROUND_TITLE,
1785     IMG_BACKGROUND_MAIN,
1786     IMG_BACKGROUND_LEVELS,
1787     IMG_BACKGROUND_SCORES,
1788     IMG_BACKGROUND_EDITOR,
1789     IMG_BACKGROUND_INFO,
1790     IMG_BACKGROUND_INFO_ELEMENTS,
1791     IMG_BACKGROUND_INFO_MUSIC,
1792     IMG_BACKGROUND_INFO_CREDITS,
1793     IMG_BACKGROUND_INFO_PROGRAM,
1794     IMG_BACKGROUND_INFO_LEVELSET,
1795     IMG_BACKGROUND_SETUP,
1796     IMG_BACKGROUND_DOOR,
1797
1798     IMG_TITLESCREEN_INITIAL_1,
1799     IMG_TITLESCREEN_INITIAL_2,
1800     IMG_TITLESCREEN_INITIAL_3,
1801     IMG_TITLESCREEN_INITIAL_4,
1802     IMG_TITLESCREEN_INITIAL_5,
1803     IMG_TITLESCREEN_1,
1804     IMG_TITLESCREEN_2,
1805     IMG_TITLESCREEN_3,
1806     IMG_TITLESCREEN_4,
1807     IMG_TITLESCREEN_5,
1808
1809     -1
1810   };
1811
1812   checked_free(graphic_info);
1813
1814   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1815
1816 #if 1
1817   /* initialize "use_image_size" flag with default value */
1818   for (i = 0; i < num_images; i++)
1819     graphic_info[i].use_image_size = FALSE;
1820
1821   /* initialize "use_image_size" flag from static configuration above */
1822   for (i = 0; full_size_graphics[i] != -1; i++)
1823     graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1824 #endif
1825
1826 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1827   if (clipmasks_initialized)
1828   {
1829     for (i = 0; i < num_images; i++)
1830     {
1831       if (graphic_info[i].clip_mask)
1832         XFreePixmap(display, graphic_info[i].clip_mask);
1833       if (graphic_info[i].clip_gc)
1834         XFreeGC(display, graphic_info[i].clip_gc);
1835
1836       graphic_info[i].clip_mask = None;
1837       graphic_info[i].clip_gc = None;
1838     }
1839   }
1840 #endif
1841
1842   /* first set all graphic paramaters ... */
1843   for (i = 0; i < num_images; i++)
1844     set_graphic_parameters(i);
1845
1846   /* ... then copy these parameters for cloned graphics */
1847   for (i = 0; i < num_images; i++)
1848     if (graphic_info[i].clone_from != -1)
1849       set_cloned_graphic_parameters(i);
1850
1851   for (i = 0; i < num_images; i++)
1852   {
1853     Bitmap *src_bitmap;
1854     int src_x, src_y;
1855     int width, height;
1856     int first_frame, last_frame;
1857     int src_bitmap_width, src_bitmap_height;
1858
1859     /* now check if no animation frames are outside of the loaded image */
1860
1861     if (graphic_info[i].bitmap == NULL)
1862       continue;         /* skip check for optional images that are undefined */
1863
1864     /* get image size (this can differ from the standard element tile size!) */
1865     width  = graphic_info[i].width;
1866     height = graphic_info[i].height;
1867
1868     /* get final bitmap size (with scaling, but without small images) */
1869     src_bitmap_width  = graphic_info[i].src_image_width;
1870     src_bitmap_height = graphic_info[i].src_image_height;
1871
1872     /* check if first animation frame is inside specified bitmap */
1873
1874     first_frame = 0;
1875     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1876
1877 #if 1
1878     /* this avoids calculating wrong start position for out-of-bounds frame */
1879     src_x = graphic_info[i].src_x;
1880     src_y = graphic_info[i].src_y;
1881 #endif
1882
1883     if (src_x < 0 || src_y < 0 ||
1884         src_x + width  > src_bitmap_width ||
1885         src_y + height > src_bitmap_height)
1886     {
1887       Error(ERR_INFO_LINE, "-");
1888       Error(ERR_INFO, "warning: error found in config file:");
1889       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1890       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1891       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1892       Error(ERR_INFO,
1893             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1894             src_x, src_y, src_bitmap_width, src_bitmap_height);
1895       Error(ERR_INFO, "custom graphic rejected for this element/action");
1896
1897       if (i == fallback_graphic)
1898         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1899
1900       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1901       Error(ERR_INFO_LINE, "-");
1902
1903       graphic_info[i] = graphic_info[fallback_graphic];
1904     }
1905
1906     /* check if last animation frame is inside specified bitmap */
1907
1908     last_frame = graphic_info[i].anim_frames - 1;
1909     getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1910
1911     if (src_x < 0 || src_y < 0 ||
1912         src_x + width  > src_bitmap_width ||
1913         src_y + height > src_bitmap_height)
1914     {
1915       Error(ERR_INFO_LINE, "-");
1916       Error(ERR_INFO, "warning: error found in config file:");
1917       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1918       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1919       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1920       Error(ERR_INFO,
1921             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1922             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1923       Error(ERR_INFO, "custom graphic rejected for this element/action");
1924
1925       if (i == fallback_graphic)
1926         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1927
1928       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1929       Error(ERR_INFO_LINE, "-");
1930
1931       graphic_info[i] = graphic_info[fallback_graphic];
1932     }
1933
1934 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1935     /* currently we only need a tile clip mask from the first frame */
1936     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1937
1938     if (copy_clipmask_gc == None)
1939     {
1940       clip_gc_values.graphics_exposures = False;
1941       clip_gc_valuemask = GCGraphicsExposures;
1942       copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1943                                    clip_gc_valuemask, &clip_gc_values);
1944     }
1945
1946     graphic_info[i].clip_mask =
1947       XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1948
1949     src_pixmap = src_bitmap->clip_mask;
1950     XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1951               copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1952
1953     clip_gc_values.graphics_exposures = False;
1954     clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1955     clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1956
1957     graphic_info[i].clip_gc =
1958       XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1959 #endif
1960   }
1961
1962 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1963   if (copy_clipmask_gc)
1964     XFreeGC(display, copy_clipmask_gc);
1965
1966   clipmasks_initialized = TRUE;
1967 #endif
1968 }
1969
1970 static void InitElementSoundInfo()
1971 {
1972   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1973   int num_property_mappings = getSoundListPropertyMappingSize();
1974   int i, j, act;
1975
1976   /* set values to -1 to identify later as "uninitialized" values */
1977   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1978     for (act = 0; act < NUM_ACTIONS; act++)
1979       element_info[i].sound[act] = -1;
1980
1981   /* initialize element/sound mapping from static configuration */
1982   for (i = 0; element_to_sound[i].element > -1; i++)
1983   {
1984     int element      = element_to_sound[i].element;
1985     int action       = element_to_sound[i].action;
1986     int sound        = element_to_sound[i].sound;
1987     boolean is_class = element_to_sound[i].is_class;
1988
1989     if (action < 0)
1990       action = ACTION_DEFAULT;
1991
1992     if (!is_class)
1993       element_info[element].sound[action] = sound;
1994     else
1995       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1996         if (strEqual(element_info[j].class_name,
1997                      element_info[element].class_name))
1998           element_info[j].sound[action] = sound;
1999   }
2000
2001   /* initialize element class/sound mapping from dynamic configuration */
2002   for (i = 0; i < num_property_mappings; i++)
2003   {
2004     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
2005     int action        = property_mapping[i].ext1_index;
2006     int sound         = property_mapping[i].artwork_index;
2007
2008     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
2009       continue;
2010
2011     if (action < 0)
2012       action = ACTION_DEFAULT;
2013
2014     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2015       if (strEqual(element_info[j].class_name,
2016                    element_info[element_class].class_name))
2017         element_info[j].sound[action] = sound;
2018   }
2019
2020   /* initialize element/sound mapping from dynamic configuration */
2021   for (i = 0; i < num_property_mappings; i++)
2022   {
2023     int element = property_mapping[i].base_index;
2024     int action  = property_mapping[i].ext1_index;
2025     int sound   = property_mapping[i].artwork_index;
2026
2027     if (element >= MAX_NUM_ELEMENTS)
2028       continue;
2029
2030     if (action < 0)
2031       action = ACTION_DEFAULT;
2032
2033     element_info[element].sound[action] = sound;
2034   }
2035
2036   /* now set all '-1' values to element specific default values */
2037   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2038   {
2039     for (act = 0; act < NUM_ACTIONS; act++)
2040     {
2041       /* generic default action sound (defined by "[default]" directive) */
2042       int default_action_sound = element_info[EL_DEFAULT].sound[act];
2043
2044       /* look for special default action sound (classic game specific) */
2045       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
2046         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
2047       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
2048         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
2049       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
2050         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
2051
2052       /* !!! there's no such thing as a "default action sound" !!! */
2053 #if 0
2054       /* look for element specific default sound (independent from action) */
2055       if (element_info[i].sound[ACTION_DEFAULT] != -1)
2056         default_action_sound = element_info[i].sound[ACTION_DEFAULT];
2057 #endif
2058
2059 #if 1
2060       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
2061       /* !!! make this better !!! */
2062       if (i == EL_EMPTY_SPACE)
2063         default_action_sound = element_info[EL_DEFAULT].sound[act];
2064 #endif
2065
2066       /* no sound for this specific action -- use default action sound */
2067       if (element_info[i].sound[act] == -1)
2068         element_info[i].sound[act] = default_action_sound;
2069     }
2070   }
2071
2072   /* copy sound settings to some elements that are only stored in level file
2073      in native R'n'D levels, but are used by game engine in native EM levels */
2074   for (i = 0; copy_properties[i][0] != -1; i++)
2075     for (j = 1; j <= 4; j++)
2076       for (act = 0; act < NUM_ACTIONS; act++)
2077         element_info[copy_properties[i][j]].sound[act] =
2078           element_info[copy_properties[i][0]].sound[act];
2079 }
2080
2081 static void InitGameModeSoundInfo()
2082 {
2083   int i;
2084
2085   /* set values to -1 to identify later as "uninitialized" values */
2086   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2087     menu.sound[i] = -1;
2088
2089   /* initialize gamemode/sound mapping from static configuration */
2090   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
2091   {
2092     int gamemode = gamemode_to_sound[i].gamemode;
2093     int sound    = gamemode_to_sound[i].sound;
2094
2095     if (gamemode < 0)
2096       gamemode = GAME_MODE_DEFAULT;
2097
2098     menu.sound[gamemode] = sound;
2099   }
2100
2101   /* now set all '-1' values to levelset specific default values */
2102   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2103     if (menu.sound[i] == -1)
2104       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
2105
2106 #if 0
2107   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2108     if (menu.sound[i] != -1)
2109       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
2110 #endif
2111 }
2112
2113 static void set_sound_parameters(int sound, char **parameter_raw)
2114 {
2115   int parameter[NUM_SND_ARGS];
2116   int i;
2117
2118   /* get integer values from string parameters */
2119   for (i = 0; i < NUM_SND_ARGS; i++)
2120     parameter[i] =
2121       get_parameter_value(parameter_raw[i],
2122                           sound_config_suffix[i].token,
2123                           sound_config_suffix[i].type);
2124
2125   /* explicit loop mode setting in configuration overrides default value */
2126   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2127     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
2128
2129   /* sound volume to change the original volume when loading the sound file */
2130   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
2131
2132   /* sound priority to give certain sounds a higher or lower priority */
2133   sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
2134 }
2135
2136 static void InitSoundInfo()
2137 {
2138   int *sound_effect_properties;
2139   int num_sounds = getSoundListSize();
2140   int i, j;
2141
2142   checked_free(sound_info);
2143
2144   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
2145   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
2146
2147   /* initialize sound effect for all elements to "no sound" */
2148   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2149     for (j = 0; j < NUM_ACTIONS; j++)
2150       element_info[i].sound[j] = SND_UNDEFINED;
2151
2152   for (i = 0; i < num_sounds; i++)
2153   {
2154     struct FileInfo *sound = getSoundListEntry(i);
2155     int len_effect_text = strlen(sound->token);
2156
2157     sound_effect_properties[i] = ACTION_OTHER;
2158     sound_info[i].loop = FALSE;         /* default: play sound only once */
2159
2160 #if 0
2161     printf("::: sound %d: '%s'\n", i, sound->token);
2162 #endif
2163
2164     /* determine all loop sounds and identify certain sound classes */
2165
2166     for (j = 0; element_action_info[j].suffix; j++)
2167     {
2168       int len_action_text = strlen(element_action_info[j].suffix);
2169
2170       if (len_action_text < len_effect_text &&
2171           strEqual(&sound->token[len_effect_text - len_action_text],
2172                    element_action_info[j].suffix))
2173       {
2174         sound_effect_properties[i] = element_action_info[j].value;
2175         sound_info[i].loop = element_action_info[j].is_loop_sound;
2176
2177         break;
2178       }
2179     }
2180
2181     /* associate elements and some selected sound actions */
2182
2183     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2184     {
2185       if (element_info[j].class_name)
2186       {
2187         int len_class_text = strlen(element_info[j].class_name);
2188
2189         if (len_class_text + 1 < len_effect_text &&
2190             strncmp(sound->token,
2191                     element_info[j].class_name, len_class_text) == 0 &&
2192             sound->token[len_class_text] == '.')
2193         {
2194           int sound_action_value = sound_effect_properties[i];
2195
2196           element_info[j].sound[sound_action_value] = i;
2197         }
2198       }
2199     }
2200
2201     set_sound_parameters(i, sound->parameter);
2202   }
2203
2204   free(sound_effect_properties);
2205 }
2206
2207 static void InitGameModeMusicInfo()
2208 {
2209   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2210   int num_property_mappings = getMusicListPropertyMappingSize();
2211   int default_levelset_music = -1;
2212   int i;
2213
2214   /* set values to -1 to identify later as "uninitialized" values */
2215   for (i = 0; i < MAX_LEVELS; i++)
2216     levelset.music[i] = -1;
2217   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2218     menu.music[i] = -1;
2219
2220   /* initialize gamemode/music mapping from static configuration */
2221   for (i = 0; gamemode_to_music[i].music > -1; i++)
2222   {
2223     int gamemode = gamemode_to_music[i].gamemode;
2224     int music    = gamemode_to_music[i].music;
2225
2226 #if 0
2227     printf("::: gamemode == %d, music == %d\n", gamemode, music);
2228 #endif
2229
2230     if (gamemode < 0)
2231       gamemode = GAME_MODE_DEFAULT;
2232
2233     menu.music[gamemode] = music;
2234   }
2235
2236   /* initialize gamemode/music mapping from dynamic configuration */
2237   for (i = 0; i < num_property_mappings; i++)
2238   {
2239     int prefix   = property_mapping[i].base_index;
2240     int gamemode = property_mapping[i].ext1_index;
2241     int level    = property_mapping[i].ext2_index;
2242     int music    = property_mapping[i].artwork_index;
2243
2244 #if 0
2245     printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
2246            prefix, gamemode, level, music);
2247 #endif
2248
2249     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2250       continue;
2251
2252     if (gamemode < 0)
2253       gamemode = GAME_MODE_DEFAULT;
2254
2255     /* level specific music only allowed for in-game music */
2256     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2257       gamemode = GAME_MODE_PLAYING;
2258
2259     if (level == -1)
2260     {
2261       level = 0;
2262       default_levelset_music = music;
2263     }
2264
2265     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2266       levelset.music[level] = music;
2267     if (gamemode != GAME_MODE_PLAYING)
2268       menu.music[gamemode] = music;
2269   }
2270
2271   /* now set all '-1' values to menu specific default values */
2272   /* (undefined values of "levelset.music[]" might stay at "-1" to
2273      allow dynamic selection of music files from music directory!) */
2274   for (i = 0; i < MAX_LEVELS; i++)
2275     if (levelset.music[i] == -1)
2276       levelset.music[i] = default_levelset_music;
2277   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2278     if (menu.music[i] == -1)
2279       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2280
2281 #if 0
2282   for (i = 0; i < MAX_LEVELS; i++)
2283     if (levelset.music[i] != -1)
2284       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
2285   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2286     if (menu.music[i] != -1)
2287       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
2288 #endif
2289 }
2290
2291 static void set_music_parameters(int music, char **parameter_raw)
2292 {
2293   int parameter[NUM_MUS_ARGS];
2294   int i;
2295
2296   /* get integer values from string parameters */
2297   for (i = 0; i < NUM_MUS_ARGS; i++)
2298     parameter[i] =
2299       get_parameter_value(parameter_raw[i],
2300                           music_config_suffix[i].token,
2301                           music_config_suffix[i].type);
2302
2303   /* explicit loop mode setting in configuration overrides default value */
2304   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2305     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2306 }
2307
2308 static void InitMusicInfo()
2309 {
2310   int num_music = getMusicListSize();
2311   int i, j;
2312
2313   checked_free(music_info);
2314
2315   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2316
2317   for (i = 0; i < num_music; i++)
2318   {
2319     struct FileInfo *music = getMusicListEntry(i);
2320     int len_music_text = strlen(music->token);
2321
2322     music_info[i].loop = TRUE;          /* default: play music in loop mode */
2323
2324     /* determine all loop music */
2325
2326     for (j = 0; music_prefix_info[j].prefix; j++)
2327     {
2328       int len_prefix_text = strlen(music_prefix_info[j].prefix);
2329
2330       if (len_prefix_text < len_music_text &&
2331           strncmp(music->token,
2332                   music_prefix_info[j].prefix, len_prefix_text) == 0)
2333       {
2334         music_info[i].loop = music_prefix_info[j].is_loop_music;
2335
2336         break;
2337       }
2338     }
2339
2340     set_music_parameters(i, music->parameter);
2341   }
2342 }
2343
2344 static void ReinitializeGraphics()
2345 {
2346   print_init_timestamp("INIT ReinitializeGraphics");
2347
2348   InitGraphicInfo();                    /* graphic properties mapping */
2349   print_init_timestamp("TIME InitGraphicInfo");
2350   InitElementGraphicInfo();             /* element game graphic mapping */
2351   print_init_timestamp("TIME InitElementGraphicInfo");
2352   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
2353   print_init_timestamp("TIME InitElementSpecialGraphicInfo");
2354
2355   InitElementSmallImages();             /* scale elements to all needed sizes */
2356   print_init_timestamp("TIME InitElementSmallImages");
2357   InitScaledImages();                   /* scale all other images, if needed */
2358   print_init_timestamp("TIME InitScaledImages");
2359   InitFontGraphicInfo();                /* initialize text drawing functions */
2360   print_init_timestamp("TIME InitFontGraphicInfo");
2361
2362   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
2363   print_init_timestamp("TIME InitGraphicInfo_EM");
2364
2365   SetMainBackgroundImage(IMG_BACKGROUND);
2366   print_init_timestamp("TIME SetMainBackgroundImage");
2367   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2368   print_init_timestamp("TIME SetDoorBackgroundImage");
2369
2370   InitGadgets();
2371   print_init_timestamp("TIME InitGadgets");
2372   InitToons();
2373   print_init_timestamp("TIME InitToons");
2374
2375   print_init_timestamp("DONE ReinitializeGraphics");
2376 }
2377
2378 static void ReinitializeSounds()
2379 {
2380   InitSoundInfo();              /* sound properties mapping */
2381   InitElementSoundInfo();       /* element game sound mapping */
2382   InitGameModeSoundInfo();      /* game mode sound mapping */
2383
2384   InitPlayLevelSound();         /* internal game sound settings */
2385 }
2386
2387 static void ReinitializeMusic()
2388 {
2389   InitMusicInfo();              /* music properties mapping */
2390   InitGameModeMusicInfo();      /* game mode music mapping */
2391 }
2392
2393 static int get_special_property_bit(int element, int property_bit_nr)
2394 {
2395   struct PropertyBitInfo
2396   {
2397     int element;
2398     int bit_nr;
2399   };
2400
2401   static struct PropertyBitInfo pb_can_move_into_acid[] =
2402   {
2403     /* the player may be able fall into acid when gravity is activated */
2404     { EL_PLAYER_1,              0       },
2405     { EL_PLAYER_2,              0       },
2406     { EL_PLAYER_3,              0       },
2407     { EL_PLAYER_4,              0       },
2408     { EL_SP_MURPHY,             0       },
2409     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2410
2411     /* all elements that can move may be able to also move into acid */
2412     { EL_BUG,                   1       },
2413     { EL_BUG_LEFT,              1       },
2414     { EL_BUG_RIGHT,             1       },
2415     { EL_BUG_UP,                1       },
2416     { EL_BUG_DOWN,              1       },
2417     { EL_SPACESHIP,             2       },
2418     { EL_SPACESHIP_LEFT,        2       },
2419     { EL_SPACESHIP_RIGHT,       2       },
2420     { EL_SPACESHIP_UP,          2       },
2421     { EL_SPACESHIP_DOWN,        2       },
2422     { EL_BD_BUTTERFLY,          3       },
2423     { EL_BD_BUTTERFLY_LEFT,     3       },
2424     { EL_BD_BUTTERFLY_RIGHT,    3       },
2425     { EL_BD_BUTTERFLY_UP,       3       },
2426     { EL_BD_BUTTERFLY_DOWN,     3       },
2427     { EL_BD_FIREFLY,            4       },
2428     { EL_BD_FIREFLY_LEFT,       4       },
2429     { EL_BD_FIREFLY_RIGHT,      4       },
2430     { EL_BD_FIREFLY_UP,         4       },
2431     { EL_BD_FIREFLY_DOWN,       4       },
2432     { EL_YAMYAM,                5       },
2433     { EL_YAMYAM_LEFT,           5       },
2434     { EL_YAMYAM_RIGHT,          5       },
2435     { EL_YAMYAM_UP,             5       },
2436     { EL_YAMYAM_DOWN,           5       },
2437     { EL_DARK_YAMYAM,           6       },
2438     { EL_ROBOT,                 7       },
2439     { EL_PACMAN,                8       },
2440     { EL_PACMAN_LEFT,           8       },
2441     { EL_PACMAN_RIGHT,          8       },
2442     { EL_PACMAN_UP,             8       },
2443     { EL_PACMAN_DOWN,           8       },
2444     { EL_MOLE,                  9       },
2445     { EL_MOLE_LEFT,             9       },
2446     { EL_MOLE_RIGHT,            9       },
2447     { EL_MOLE_UP,               9       },
2448     { EL_MOLE_DOWN,             9       },
2449     { EL_PENGUIN,               10      },
2450     { EL_PIG,                   11      },
2451     { EL_DRAGON,                12      },
2452     { EL_SATELLITE,             13      },
2453     { EL_SP_SNIKSNAK,           14      },
2454     { EL_SP_ELECTRON,           15      },
2455     { EL_BALLOON,               16      },
2456     { EL_SPRING,                17      },
2457     { EL_EMC_ANDROID,           18      },
2458
2459     { -1,                       -1      },
2460   };
2461
2462   static struct PropertyBitInfo pb_dont_collide_with[] =
2463   {
2464     { EL_SP_SNIKSNAK,           0       },
2465     { EL_SP_ELECTRON,           1       },
2466
2467     { -1,                       -1      },
2468   };
2469
2470   static struct
2471   {
2472     int bit_nr;
2473     struct PropertyBitInfo *pb_info;
2474   } pb_definition[] =
2475   {
2476     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2477     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2478
2479     { -1,                       NULL                    },
2480   };
2481
2482   struct PropertyBitInfo *pb_info = NULL;
2483   int i;
2484
2485   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2486     if (pb_definition[i].bit_nr == property_bit_nr)
2487       pb_info = pb_definition[i].pb_info;
2488
2489   if (pb_info == NULL)
2490     return -1;
2491
2492   for (i = 0; pb_info[i].element != -1; i++)
2493     if (pb_info[i].element == element)
2494       return pb_info[i].bit_nr;
2495
2496   return -1;
2497 }
2498
2499 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2500                          boolean property_value)
2501 {
2502   int bit_nr = get_special_property_bit(element, property_bit_nr);
2503
2504   if (bit_nr > -1)
2505   {
2506     if (property_value)
2507       *bitfield |=  (1 << bit_nr);
2508     else
2509       *bitfield &= ~(1 << bit_nr);
2510   }
2511 }
2512
2513 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2514 {
2515   int bit_nr = get_special_property_bit(element, property_bit_nr);
2516
2517   if (bit_nr > -1)
2518     return ((*bitfield & (1 << bit_nr)) != 0);
2519
2520   return FALSE;
2521 }
2522
2523 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2524 {
2525   static int group_nr;
2526   static struct ElementGroupInfo *group;
2527   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2528   int i;
2529
2530   if (actual_group == NULL)                     /* not yet initialized */
2531     return;
2532
2533   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
2534   {
2535     Error(ERR_WARN, "recursion too deep when resolving group element %d",
2536           group_element - EL_GROUP_START + 1);
2537
2538     /* replace element which caused too deep recursion by question mark */
2539     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2540
2541     return;
2542   }
2543
2544   if (recursion_depth == 0)                     /* initialization */
2545   {
2546     group = actual_group;
2547     group_nr = GROUP_NR(group_element);
2548
2549     group->num_elements_resolved = 0;
2550     group->choice_pos = 0;
2551
2552     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2553       element_info[i].in_group[group_nr] = FALSE;
2554   }
2555
2556   for (i = 0; i < actual_group->num_elements; i++)
2557   {
2558     int element = actual_group->element[i];
2559
2560     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2561       break;
2562
2563     if (IS_GROUP_ELEMENT(element))
2564       ResolveGroupElementExt(element, recursion_depth + 1);
2565     else
2566     {
2567       group->element_resolved[group->num_elements_resolved++] = element;
2568       element_info[element].in_group[group_nr] = TRUE;
2569     }
2570   }
2571 }
2572
2573 void ResolveGroupElement(int group_element)
2574 {
2575   ResolveGroupElementExt(group_element, 0);
2576 }
2577
2578 void InitElementPropertiesStatic()
2579 {
2580   static int ep_diggable[] =
2581   {
2582     EL_SAND,
2583     EL_SP_BASE,
2584     EL_SP_BUGGY_BASE,
2585     EL_SP_BUGGY_BASE_ACTIVATING,
2586     EL_TRAP,
2587     EL_INVISIBLE_SAND,
2588     EL_INVISIBLE_SAND_ACTIVE,
2589     EL_EMC_GRASS,
2590
2591     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2592     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2593 #if 0
2594     EL_LANDMINE,
2595     EL_DC_LANDMINE,
2596     EL_TRAP_ACTIVE,
2597     EL_SP_BUGGY_BASE_ACTIVE,
2598     EL_EMC_PLANT,
2599 #endif
2600
2601     -1
2602   };
2603
2604   static int ep_collectible_only[] =
2605   {
2606     EL_BD_DIAMOND,
2607     EL_EMERALD,
2608     EL_DIAMOND,
2609     EL_EMERALD_YELLOW,
2610     EL_EMERALD_RED,
2611     EL_EMERALD_PURPLE,
2612     EL_KEY_1,
2613     EL_KEY_2,
2614     EL_KEY_3,
2615     EL_KEY_4,
2616     EL_EM_KEY_1,
2617     EL_EM_KEY_2,
2618     EL_EM_KEY_3,
2619     EL_EM_KEY_4,
2620     EL_EMC_KEY_5,
2621     EL_EMC_KEY_6,
2622     EL_EMC_KEY_7,
2623     EL_EMC_KEY_8,
2624     EL_DYNAMITE,
2625     EL_EM_DYNAMITE,
2626     EL_DYNABOMB_INCREASE_NUMBER,
2627     EL_DYNABOMB_INCREASE_SIZE,
2628     EL_DYNABOMB_INCREASE_POWER,
2629     EL_SP_INFOTRON,
2630     EL_SP_DISK_RED,
2631     EL_PEARL,
2632     EL_CRYSTAL,
2633     EL_DC_KEY_WHITE,
2634     EL_SHIELD_NORMAL,
2635     EL_SHIELD_DEADLY,
2636     EL_EXTRA_TIME,
2637     EL_ENVELOPE_1,
2638     EL_ENVELOPE_2,
2639     EL_ENVELOPE_3,
2640     EL_ENVELOPE_4,
2641     EL_SPEED_PILL,
2642     EL_EMC_LENSES,
2643     EL_EMC_MAGNIFIER,
2644
2645 #if 0
2646     /* !!! handle separately !!! */
2647     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2648 #endif
2649
2650     -1
2651   };
2652
2653   static int ep_dont_run_into[] =
2654   {
2655     /* same elements as in 'ep_dont_touch' */
2656     EL_BUG,
2657     EL_SPACESHIP,
2658     EL_BD_BUTTERFLY,
2659     EL_BD_FIREFLY,
2660
2661     /* same elements as in 'ep_dont_collide_with' */
2662     EL_YAMYAM,
2663     EL_DARK_YAMYAM,
2664     EL_ROBOT,
2665     EL_PACMAN,
2666     EL_SP_SNIKSNAK,
2667     EL_SP_ELECTRON,
2668
2669     /* new elements */
2670     EL_AMOEBA_DROP,
2671     EL_ACID,
2672
2673     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2674 #if 1
2675     EL_LANDMINE,
2676     EL_DC_LANDMINE,
2677     EL_TRAP_ACTIVE,
2678     EL_SP_BUGGY_BASE_ACTIVE,
2679     EL_EMC_PLANT,
2680 #endif
2681
2682     -1
2683   };
2684
2685   static int ep_dont_collide_with[] =
2686   {
2687     /* same elements as in 'ep_dont_touch' */
2688     EL_BUG,
2689     EL_SPACESHIP,
2690     EL_BD_BUTTERFLY,
2691     EL_BD_FIREFLY,
2692
2693     /* new elements */
2694     EL_YAMYAM,
2695     EL_DARK_YAMYAM,
2696     EL_ROBOT,
2697     EL_PACMAN,
2698     EL_SP_SNIKSNAK,
2699     EL_SP_ELECTRON,
2700
2701     -1
2702   };
2703
2704   static int ep_dont_touch[] =
2705   {
2706     EL_BUG,
2707     EL_SPACESHIP,
2708     EL_BD_BUTTERFLY,
2709     EL_BD_FIREFLY,
2710
2711     -1
2712   };
2713
2714   static int ep_indestructible[] =
2715   {
2716     EL_STEELWALL,
2717     EL_ACID,
2718     EL_ACID_POOL_TOPLEFT,
2719     EL_ACID_POOL_TOPRIGHT,
2720     EL_ACID_POOL_BOTTOMLEFT,
2721     EL_ACID_POOL_BOTTOM,
2722     EL_ACID_POOL_BOTTOMRIGHT,
2723     EL_SP_HARDWARE_GRAY,
2724     EL_SP_HARDWARE_GREEN,
2725     EL_SP_HARDWARE_BLUE,
2726     EL_SP_HARDWARE_RED,
2727     EL_SP_HARDWARE_YELLOW,
2728     EL_SP_HARDWARE_BASE_1,
2729     EL_SP_HARDWARE_BASE_2,
2730     EL_SP_HARDWARE_BASE_3,
2731     EL_SP_HARDWARE_BASE_4,
2732     EL_SP_HARDWARE_BASE_5,
2733     EL_SP_HARDWARE_BASE_6,
2734     EL_INVISIBLE_STEELWALL,
2735     EL_INVISIBLE_STEELWALL_ACTIVE,
2736     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2737     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2738     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2739     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2740     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2741     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2742     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2743     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2744     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2745     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2746     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2747     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2748     EL_LIGHT_SWITCH,
2749     EL_LIGHT_SWITCH_ACTIVE,
2750     EL_SIGN_EXCLAMATION,
2751     EL_SIGN_RADIOACTIVITY,
2752     EL_SIGN_STOP,
2753     EL_SIGN_WHEELCHAIR,
2754     EL_SIGN_PARKING,
2755     EL_SIGN_NO_ENTRY,
2756     EL_SIGN_UNUSED_1,
2757     EL_SIGN_GIVE_WAY,
2758     EL_SIGN_ENTRY_FORBIDDEN,
2759     EL_SIGN_EMERGENCY_EXIT,
2760     EL_SIGN_YIN_YANG,
2761     EL_SIGN_UNUSED_2,
2762     EL_SIGN_SPERMS,
2763     EL_SIGN_BULLET,
2764     EL_SIGN_HEART,
2765     EL_SIGN_CROSS,
2766     EL_SIGN_FRANKIE,
2767     EL_STEEL_EXIT_CLOSED,
2768     EL_STEEL_EXIT_OPEN,
2769     EL_EM_STEEL_EXIT_CLOSED,
2770     EL_EM_STEEL_EXIT_OPEN,
2771     EL_DC_STEELWALL_1_LEFT,
2772     EL_DC_STEELWALL_1_RIGHT,
2773     EL_DC_STEELWALL_1_TOP,
2774     EL_DC_STEELWALL_1_BOTTOM,
2775     EL_DC_STEELWALL_1_HORIZONTAL,
2776     EL_DC_STEELWALL_1_VERTICAL,
2777     EL_DC_STEELWALL_1_TOPLEFT,
2778     EL_DC_STEELWALL_1_TOPRIGHT,
2779     EL_DC_STEELWALL_1_BOTTOMLEFT,
2780     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2781     EL_DC_STEELWALL_1_TOPLEFT_2,
2782     EL_DC_STEELWALL_1_TOPRIGHT_2,
2783     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2784     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2785     EL_DC_STEELWALL_2_LEFT,
2786     EL_DC_STEELWALL_2_RIGHT,
2787     EL_DC_STEELWALL_2_TOP,
2788     EL_DC_STEELWALL_2_BOTTOM,
2789     EL_DC_STEELWALL_2_HORIZONTAL,
2790     EL_DC_STEELWALL_2_VERTICAL,
2791     EL_DC_STEELWALL_2_MIDDLE,
2792     EL_DC_STEELWALL_2_SINGLE,
2793     EL_STEELWALL_SLIPPERY,
2794     EL_EMC_STEELWALL_1,
2795     EL_EMC_STEELWALL_2,
2796     EL_EMC_STEELWALL_3,
2797     EL_EMC_STEELWALL_4,
2798     EL_CRYSTAL,
2799     EL_GATE_1,
2800     EL_GATE_2,
2801     EL_GATE_3,
2802     EL_GATE_4,
2803     EL_GATE_1_GRAY,
2804     EL_GATE_2_GRAY,
2805     EL_GATE_3_GRAY,
2806     EL_GATE_4_GRAY,
2807     EL_GATE_1_GRAY_ACTIVE,
2808     EL_GATE_2_GRAY_ACTIVE,
2809     EL_GATE_3_GRAY_ACTIVE,
2810     EL_GATE_4_GRAY_ACTIVE,
2811     EL_EM_GATE_1,
2812     EL_EM_GATE_2,
2813     EL_EM_GATE_3,
2814     EL_EM_GATE_4,
2815     EL_EM_GATE_1_GRAY,
2816     EL_EM_GATE_2_GRAY,
2817     EL_EM_GATE_3_GRAY,
2818     EL_EM_GATE_4_GRAY,
2819     EL_EM_GATE_1_GRAY_ACTIVE,
2820     EL_EM_GATE_2_GRAY_ACTIVE,
2821     EL_EM_GATE_3_GRAY_ACTIVE,
2822     EL_EM_GATE_4_GRAY_ACTIVE,
2823     EL_EMC_GATE_5,
2824     EL_EMC_GATE_6,
2825     EL_EMC_GATE_7,
2826     EL_EMC_GATE_8,
2827     EL_EMC_GATE_5_GRAY,
2828     EL_EMC_GATE_6_GRAY,
2829     EL_EMC_GATE_7_GRAY,
2830     EL_EMC_GATE_8_GRAY,
2831     EL_EMC_GATE_5_GRAY_ACTIVE,
2832     EL_EMC_GATE_6_GRAY_ACTIVE,
2833     EL_EMC_GATE_7_GRAY_ACTIVE,
2834     EL_EMC_GATE_8_GRAY_ACTIVE,
2835     EL_DC_GATE_WHITE,
2836     EL_DC_GATE_WHITE_GRAY,
2837     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2838     EL_DC_GATE_FAKE_GRAY,
2839     EL_SWITCHGATE_OPEN,
2840     EL_SWITCHGATE_OPENING,
2841     EL_SWITCHGATE_CLOSED,
2842     EL_SWITCHGATE_CLOSING,
2843 #if 1
2844     EL_DC_SWITCHGATE_SWITCH_UP,
2845     EL_DC_SWITCHGATE_SWITCH_DOWN,
2846 #endif
2847     EL_TIMEGATE_OPEN,
2848     EL_TIMEGATE_OPENING,
2849     EL_TIMEGATE_CLOSED,
2850     EL_TIMEGATE_CLOSING,
2851 #if 1
2852     EL_DC_TIMEGATE_SWITCH,
2853     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2854 #endif
2855     EL_TUBE_ANY,
2856     EL_TUBE_VERTICAL,
2857     EL_TUBE_HORIZONTAL,
2858     EL_TUBE_VERTICAL_LEFT,
2859     EL_TUBE_VERTICAL_RIGHT,
2860     EL_TUBE_HORIZONTAL_UP,
2861     EL_TUBE_HORIZONTAL_DOWN,
2862     EL_TUBE_LEFT_UP,
2863     EL_TUBE_LEFT_DOWN,
2864     EL_TUBE_RIGHT_UP,
2865     EL_TUBE_RIGHT_DOWN,
2866     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2867     EL_EXPANDABLE_STEELWALL_VERTICAL,
2868     EL_EXPANDABLE_STEELWALL_ANY,
2869
2870     -1
2871   };
2872
2873   static int ep_slippery[] =
2874   {
2875     EL_WALL_SLIPPERY,
2876     EL_BD_WALL,
2877     EL_ROCK,
2878     EL_BD_ROCK,
2879     EL_EMERALD,
2880     EL_BD_DIAMOND,
2881     EL_EMERALD_YELLOW,
2882     EL_EMERALD_RED,
2883     EL_EMERALD_PURPLE,
2884     EL_DIAMOND,
2885     EL_BOMB,
2886     EL_NUT,
2887     EL_ROBOT_WHEEL_ACTIVE,
2888     EL_ROBOT_WHEEL,
2889     EL_TIME_ORB_FULL,
2890     EL_TIME_ORB_EMPTY,
2891     EL_LAMP_ACTIVE,
2892     EL_LAMP,
2893     EL_ACID_POOL_TOPLEFT,
2894     EL_ACID_POOL_TOPRIGHT,
2895     EL_SATELLITE,
2896     EL_SP_ZONK,
2897     EL_SP_INFOTRON,
2898     EL_SP_CHIP_SINGLE,
2899     EL_SP_CHIP_LEFT,
2900     EL_SP_CHIP_RIGHT,
2901     EL_SP_CHIP_TOP,
2902     EL_SP_CHIP_BOTTOM,
2903     EL_SPEED_PILL,
2904     EL_STEELWALL_SLIPPERY,
2905     EL_PEARL,
2906     EL_CRYSTAL,
2907     EL_EMC_WALL_SLIPPERY_1,
2908     EL_EMC_WALL_SLIPPERY_2,
2909     EL_EMC_WALL_SLIPPERY_3,
2910     EL_EMC_WALL_SLIPPERY_4,
2911     EL_EMC_MAGIC_BALL,
2912     EL_EMC_MAGIC_BALL_ACTIVE,
2913
2914     -1
2915   };
2916
2917   static int ep_can_change[] =
2918   {
2919     -1
2920   };
2921
2922   static int ep_can_move[] =
2923   {
2924     /* same elements as in 'pb_can_move_into_acid' */
2925     EL_BUG,
2926     EL_SPACESHIP,
2927     EL_BD_BUTTERFLY,
2928     EL_BD_FIREFLY,
2929     EL_YAMYAM,
2930     EL_DARK_YAMYAM,
2931     EL_ROBOT,
2932     EL_PACMAN,
2933     EL_MOLE,
2934     EL_PENGUIN,
2935     EL_PIG,
2936     EL_DRAGON,
2937     EL_SATELLITE,
2938     EL_SP_SNIKSNAK,
2939     EL_SP_ELECTRON,
2940     EL_BALLOON,
2941     EL_SPRING,
2942     EL_EMC_ANDROID,
2943
2944     -1
2945   };
2946
2947   static int ep_can_fall[] =
2948   {
2949     EL_ROCK,
2950     EL_BD_ROCK,
2951     EL_EMERALD,
2952     EL_BD_DIAMOND,
2953     EL_EMERALD_YELLOW,
2954     EL_EMERALD_RED,
2955     EL_EMERALD_PURPLE,
2956     EL_DIAMOND,
2957     EL_BOMB,
2958     EL_NUT,
2959     EL_AMOEBA_DROP,
2960     EL_QUICKSAND_FULL,
2961     EL_QUICKSAND_FAST_FULL,
2962     EL_MAGIC_WALL_FULL,
2963     EL_BD_MAGIC_WALL_FULL,
2964     EL_DC_MAGIC_WALL_FULL,
2965     EL_TIME_ORB_FULL,
2966     EL_TIME_ORB_EMPTY,
2967     EL_SP_ZONK,
2968     EL_SP_INFOTRON,
2969     EL_SP_DISK_ORANGE,
2970     EL_PEARL,
2971     EL_CRYSTAL,
2972     EL_SPRING,
2973     EL_DX_SUPABOMB,
2974
2975     -1
2976   };
2977
2978   static int ep_can_smash_player[] =
2979   {
2980     EL_ROCK,
2981     EL_BD_ROCK,
2982     EL_EMERALD,
2983     EL_BD_DIAMOND,
2984     EL_EMERALD_YELLOW,
2985     EL_EMERALD_RED,
2986     EL_EMERALD_PURPLE,
2987     EL_DIAMOND,
2988     EL_BOMB,
2989     EL_NUT,
2990     EL_AMOEBA_DROP,
2991     EL_TIME_ORB_FULL,
2992     EL_TIME_ORB_EMPTY,
2993     EL_SP_ZONK,
2994     EL_SP_INFOTRON,
2995     EL_SP_DISK_ORANGE,
2996     EL_PEARL,
2997     EL_CRYSTAL,
2998     EL_SPRING,
2999     EL_DX_SUPABOMB,
3000
3001     -1
3002   };
3003
3004   static int ep_can_smash_enemies[] =
3005   {
3006     EL_ROCK,
3007     EL_BD_ROCK,
3008     EL_SP_ZONK,
3009
3010     -1
3011   };
3012
3013   static int ep_can_smash_everything[] =
3014   {
3015     EL_ROCK,
3016     EL_BD_ROCK,
3017     EL_SP_ZONK,
3018
3019     -1
3020   };
3021
3022   static int ep_explodes_by_fire[] =
3023   {
3024     /* same elements as in 'ep_explodes_impact' */
3025     EL_BOMB,
3026     EL_SP_DISK_ORANGE,
3027     EL_DX_SUPABOMB,
3028
3029     /* same elements as in 'ep_explodes_smashed' */
3030     EL_SATELLITE,
3031     EL_PIG,
3032     EL_DRAGON,
3033     EL_MOLE,
3034
3035     /* new elements */
3036     EL_DYNAMITE,
3037     EL_DYNAMITE_ACTIVE,
3038     EL_EM_DYNAMITE,
3039     EL_EM_DYNAMITE_ACTIVE,
3040     EL_DYNABOMB_PLAYER_1_ACTIVE,
3041     EL_DYNABOMB_PLAYER_2_ACTIVE,
3042     EL_DYNABOMB_PLAYER_3_ACTIVE,
3043     EL_DYNABOMB_PLAYER_4_ACTIVE,
3044     EL_DYNABOMB_INCREASE_NUMBER,
3045     EL_DYNABOMB_INCREASE_SIZE,
3046     EL_DYNABOMB_INCREASE_POWER,
3047     EL_SP_DISK_RED_ACTIVE,
3048     EL_BUG,
3049     EL_PENGUIN,
3050     EL_SP_DISK_RED,
3051     EL_SP_DISK_YELLOW,
3052     EL_SP_SNIKSNAK,
3053     EL_SP_ELECTRON,
3054 #if 0
3055     EL_BLACK_ORB,
3056 #endif
3057
3058     -1
3059   };
3060
3061   static int ep_explodes_smashed[] =
3062   {
3063     /* same elements as in 'ep_explodes_impact' */
3064     EL_BOMB,
3065     EL_SP_DISK_ORANGE,
3066     EL_DX_SUPABOMB,
3067
3068     /* new elements */
3069     EL_SATELLITE,
3070     EL_PIG,
3071     EL_DRAGON,
3072     EL_MOLE,
3073
3074     -1
3075   };
3076
3077   static int ep_explodes_impact[] =
3078   {
3079     EL_BOMB,
3080     EL_SP_DISK_ORANGE,
3081     EL_DX_SUPABOMB,
3082
3083     -1
3084   };
3085
3086   static int ep_walkable_over[] =
3087   {
3088     EL_EMPTY_SPACE,
3089     EL_SP_EMPTY_SPACE,
3090     EL_SOKOBAN_FIELD_EMPTY,
3091     EL_EXIT_OPEN,
3092     EL_EM_EXIT_OPEN,
3093     EL_SP_EXIT_OPEN,
3094     EL_SP_EXIT_OPENING,
3095     EL_STEEL_EXIT_OPEN,
3096     EL_EM_STEEL_EXIT_OPEN,
3097     EL_GATE_1,
3098     EL_GATE_2,
3099     EL_GATE_3,
3100     EL_GATE_4,
3101     EL_GATE_1_GRAY,
3102     EL_GATE_2_GRAY,
3103     EL_GATE_3_GRAY,
3104     EL_GATE_4_GRAY,
3105     EL_GATE_1_GRAY_ACTIVE,
3106     EL_GATE_2_GRAY_ACTIVE,
3107     EL_GATE_3_GRAY_ACTIVE,
3108     EL_GATE_4_GRAY_ACTIVE,
3109     EL_PENGUIN,
3110     EL_PIG,
3111     EL_DRAGON,
3112
3113     -1
3114   };
3115
3116   static int ep_walkable_inside[] =
3117   {
3118     EL_TUBE_ANY,
3119     EL_TUBE_VERTICAL,
3120     EL_TUBE_HORIZONTAL,
3121     EL_TUBE_VERTICAL_LEFT,
3122     EL_TUBE_VERTICAL_RIGHT,
3123     EL_TUBE_HORIZONTAL_UP,
3124     EL_TUBE_HORIZONTAL_DOWN,
3125     EL_TUBE_LEFT_UP,
3126     EL_TUBE_LEFT_DOWN,
3127     EL_TUBE_RIGHT_UP,
3128     EL_TUBE_RIGHT_DOWN,
3129
3130     -1
3131   };
3132
3133   static int ep_walkable_under[] =
3134   {
3135     -1
3136   };
3137
3138   static int ep_passable_over[] =
3139   {
3140     EL_EM_GATE_1,
3141     EL_EM_GATE_2,
3142     EL_EM_GATE_3,
3143     EL_EM_GATE_4,
3144     EL_EM_GATE_1_GRAY,
3145     EL_EM_GATE_2_GRAY,
3146     EL_EM_GATE_3_GRAY,
3147     EL_EM_GATE_4_GRAY,
3148     EL_EM_GATE_1_GRAY_ACTIVE,
3149     EL_EM_GATE_2_GRAY_ACTIVE,
3150     EL_EM_GATE_3_GRAY_ACTIVE,
3151     EL_EM_GATE_4_GRAY_ACTIVE,
3152     EL_EMC_GATE_5,
3153     EL_EMC_GATE_6,
3154     EL_EMC_GATE_7,
3155     EL_EMC_GATE_8,
3156     EL_EMC_GATE_5_GRAY,
3157     EL_EMC_GATE_6_GRAY,
3158     EL_EMC_GATE_7_GRAY,
3159     EL_EMC_GATE_8_GRAY,
3160     EL_EMC_GATE_5_GRAY_ACTIVE,
3161     EL_EMC_GATE_6_GRAY_ACTIVE,
3162     EL_EMC_GATE_7_GRAY_ACTIVE,
3163     EL_EMC_GATE_8_GRAY_ACTIVE,
3164     EL_DC_GATE_WHITE,
3165     EL_DC_GATE_WHITE_GRAY,
3166     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3167     EL_SWITCHGATE_OPEN,
3168     EL_TIMEGATE_OPEN,
3169
3170     -1
3171   };
3172
3173   static int ep_passable_inside[] =
3174   {
3175     EL_SP_PORT_LEFT,
3176     EL_SP_PORT_RIGHT,
3177     EL_SP_PORT_UP,
3178     EL_SP_PORT_DOWN,
3179     EL_SP_PORT_HORIZONTAL,
3180     EL_SP_PORT_VERTICAL,
3181     EL_SP_PORT_ANY,
3182     EL_SP_GRAVITY_PORT_LEFT,
3183     EL_SP_GRAVITY_PORT_RIGHT,
3184     EL_SP_GRAVITY_PORT_UP,
3185     EL_SP_GRAVITY_PORT_DOWN,
3186     EL_SP_GRAVITY_ON_PORT_LEFT,
3187     EL_SP_GRAVITY_ON_PORT_RIGHT,
3188     EL_SP_GRAVITY_ON_PORT_UP,
3189     EL_SP_GRAVITY_ON_PORT_DOWN,
3190     EL_SP_GRAVITY_OFF_PORT_LEFT,
3191     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3192     EL_SP_GRAVITY_OFF_PORT_UP,
3193     EL_SP_GRAVITY_OFF_PORT_DOWN,
3194
3195     -1
3196   };
3197
3198   static int ep_passable_under[] =
3199   {
3200     -1
3201   };
3202
3203   static int ep_droppable[] =
3204   {
3205     -1
3206   };
3207
3208   static int ep_explodes_1x1_old[] =
3209   {
3210     -1
3211   };
3212
3213   static int ep_pushable[] =
3214   {
3215     EL_ROCK,
3216     EL_BOMB,
3217     EL_DX_SUPABOMB,
3218     EL_NUT,
3219     EL_TIME_ORB_EMPTY,
3220     EL_SP_ZONK,
3221     EL_SP_DISK_ORANGE,
3222     EL_SPRING,
3223     EL_BD_ROCK,
3224     EL_SOKOBAN_OBJECT,
3225     EL_SOKOBAN_FIELD_FULL,
3226     EL_SATELLITE,
3227     EL_SP_DISK_YELLOW,
3228     EL_BALLOON,
3229     EL_EMC_ANDROID,
3230
3231     -1
3232   };
3233
3234   static int ep_explodes_cross_old[] =
3235   {
3236     -1
3237   };
3238
3239   static int ep_protected[] =
3240   {
3241     /* same elements as in 'ep_walkable_inside' */
3242     EL_TUBE_ANY,
3243     EL_TUBE_VERTICAL,
3244     EL_TUBE_HORIZONTAL,
3245     EL_TUBE_VERTICAL_LEFT,
3246     EL_TUBE_VERTICAL_RIGHT,
3247     EL_TUBE_HORIZONTAL_UP,
3248     EL_TUBE_HORIZONTAL_DOWN,
3249     EL_TUBE_LEFT_UP,
3250     EL_TUBE_LEFT_DOWN,
3251     EL_TUBE_RIGHT_UP,
3252     EL_TUBE_RIGHT_DOWN,
3253
3254     /* same elements as in 'ep_passable_over' */
3255     EL_EM_GATE_1,
3256     EL_EM_GATE_2,
3257     EL_EM_GATE_3,
3258     EL_EM_GATE_4,
3259     EL_EM_GATE_1_GRAY,
3260     EL_EM_GATE_2_GRAY,
3261     EL_EM_GATE_3_GRAY,
3262     EL_EM_GATE_4_GRAY,
3263     EL_EM_GATE_1_GRAY_ACTIVE,
3264     EL_EM_GATE_2_GRAY_ACTIVE,
3265     EL_EM_GATE_3_GRAY_ACTIVE,
3266     EL_EM_GATE_4_GRAY_ACTIVE,
3267     EL_EMC_GATE_5,
3268     EL_EMC_GATE_6,
3269     EL_EMC_GATE_7,
3270     EL_EMC_GATE_8,
3271     EL_EMC_GATE_5_GRAY,
3272     EL_EMC_GATE_6_GRAY,
3273     EL_EMC_GATE_7_GRAY,
3274     EL_EMC_GATE_8_GRAY,
3275     EL_EMC_GATE_5_GRAY_ACTIVE,
3276     EL_EMC_GATE_6_GRAY_ACTIVE,
3277     EL_EMC_GATE_7_GRAY_ACTIVE,
3278     EL_EMC_GATE_8_GRAY_ACTIVE,
3279     EL_DC_GATE_WHITE,
3280     EL_DC_GATE_WHITE_GRAY,
3281     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3282     EL_SWITCHGATE_OPEN,
3283     EL_TIMEGATE_OPEN,
3284
3285     /* same elements as in 'ep_passable_inside' */
3286     EL_SP_PORT_LEFT,
3287     EL_SP_PORT_RIGHT,
3288     EL_SP_PORT_UP,
3289     EL_SP_PORT_DOWN,
3290     EL_SP_PORT_HORIZONTAL,
3291     EL_SP_PORT_VERTICAL,
3292     EL_SP_PORT_ANY,
3293     EL_SP_GRAVITY_PORT_LEFT,
3294     EL_SP_GRAVITY_PORT_RIGHT,
3295     EL_SP_GRAVITY_PORT_UP,
3296     EL_SP_GRAVITY_PORT_DOWN,
3297     EL_SP_GRAVITY_ON_PORT_LEFT,
3298     EL_SP_GRAVITY_ON_PORT_RIGHT,
3299     EL_SP_GRAVITY_ON_PORT_UP,
3300     EL_SP_GRAVITY_ON_PORT_DOWN,
3301     EL_SP_GRAVITY_OFF_PORT_LEFT,
3302     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3303     EL_SP_GRAVITY_OFF_PORT_UP,
3304     EL_SP_GRAVITY_OFF_PORT_DOWN,
3305
3306     -1
3307   };
3308
3309   static int ep_throwable[] =
3310   {
3311     -1
3312   };
3313
3314   static int ep_can_explode[] =
3315   {
3316     /* same elements as in 'ep_explodes_impact' */
3317     EL_BOMB,
3318     EL_SP_DISK_ORANGE,
3319     EL_DX_SUPABOMB,
3320
3321     /* same elements as in 'ep_explodes_smashed' */
3322     EL_SATELLITE,
3323     EL_PIG,
3324     EL_DRAGON,
3325     EL_MOLE,
3326
3327     /* elements that can explode by explosion or by dragonfire */
3328     EL_DYNAMITE,
3329     EL_DYNAMITE_ACTIVE,
3330     EL_EM_DYNAMITE,
3331     EL_EM_DYNAMITE_ACTIVE,
3332     EL_DYNABOMB_PLAYER_1_ACTIVE,
3333     EL_DYNABOMB_PLAYER_2_ACTIVE,
3334     EL_DYNABOMB_PLAYER_3_ACTIVE,
3335     EL_DYNABOMB_PLAYER_4_ACTIVE,
3336     EL_DYNABOMB_INCREASE_NUMBER,
3337     EL_DYNABOMB_INCREASE_SIZE,
3338     EL_DYNABOMB_INCREASE_POWER,
3339     EL_SP_DISK_RED_ACTIVE,
3340     EL_BUG,
3341     EL_PENGUIN,
3342     EL_SP_DISK_RED,
3343     EL_SP_DISK_YELLOW,
3344     EL_SP_SNIKSNAK,
3345     EL_SP_ELECTRON,
3346
3347     /* elements that can explode only by explosion */
3348     EL_BLACK_ORB,
3349
3350     -1
3351   };
3352
3353   static int ep_gravity_reachable[] =
3354   {
3355     EL_SAND,
3356     EL_SP_BASE,
3357     EL_TRAP,
3358     EL_INVISIBLE_SAND,
3359     EL_INVISIBLE_SAND_ACTIVE,
3360     EL_SP_PORT_LEFT,
3361     EL_SP_PORT_RIGHT,
3362     EL_SP_PORT_UP,
3363     EL_SP_PORT_DOWN,
3364     EL_SP_PORT_HORIZONTAL,
3365     EL_SP_PORT_VERTICAL,
3366     EL_SP_PORT_ANY,
3367     EL_SP_GRAVITY_PORT_LEFT,
3368     EL_SP_GRAVITY_PORT_RIGHT,
3369     EL_SP_GRAVITY_PORT_UP,
3370     EL_SP_GRAVITY_PORT_DOWN,
3371     EL_SP_GRAVITY_ON_PORT_LEFT,
3372     EL_SP_GRAVITY_ON_PORT_RIGHT,
3373     EL_SP_GRAVITY_ON_PORT_UP,
3374     EL_SP_GRAVITY_ON_PORT_DOWN,
3375     EL_SP_GRAVITY_OFF_PORT_LEFT,
3376     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3377     EL_SP_GRAVITY_OFF_PORT_UP,
3378     EL_SP_GRAVITY_OFF_PORT_DOWN,
3379     EL_EMC_GRASS,
3380
3381     -1
3382   };
3383
3384   static int ep_player[] =
3385   {
3386     EL_PLAYER_1,
3387     EL_PLAYER_2,
3388     EL_PLAYER_3,
3389     EL_PLAYER_4,
3390     EL_SP_MURPHY,
3391     EL_SOKOBAN_FIELD_PLAYER,
3392     EL_TRIGGER_PLAYER,
3393
3394     -1
3395   };
3396
3397   static int ep_can_pass_magic_wall[] =
3398   {
3399     EL_ROCK,
3400     EL_BD_ROCK,
3401     EL_EMERALD,
3402     EL_BD_DIAMOND,
3403     EL_EMERALD_YELLOW,
3404     EL_EMERALD_RED,
3405     EL_EMERALD_PURPLE,
3406     EL_DIAMOND,
3407
3408     -1
3409   };
3410
3411   static int ep_can_pass_dc_magic_wall[] =
3412   {
3413     EL_ROCK,
3414     EL_BD_ROCK,
3415     EL_EMERALD,
3416     EL_BD_DIAMOND,
3417     EL_EMERALD_YELLOW,
3418     EL_EMERALD_RED,
3419     EL_EMERALD_PURPLE,
3420     EL_DIAMOND,
3421     EL_PEARL,
3422     EL_CRYSTAL,
3423
3424     -1
3425   };
3426
3427   static int ep_switchable[] =
3428   {
3429     EL_ROBOT_WHEEL,
3430     EL_SP_TERMINAL,
3431     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3432     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3433     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3434     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3435     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3436     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3437     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3438     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3439     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3440     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3441     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3442     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3443     EL_SWITCHGATE_SWITCH_UP,
3444     EL_SWITCHGATE_SWITCH_DOWN,
3445     EL_DC_SWITCHGATE_SWITCH_UP,
3446     EL_DC_SWITCHGATE_SWITCH_DOWN,
3447     EL_LIGHT_SWITCH,
3448     EL_LIGHT_SWITCH_ACTIVE,
3449     EL_TIMEGATE_SWITCH,
3450     EL_DC_TIMEGATE_SWITCH,
3451     EL_BALLOON_SWITCH_LEFT,
3452     EL_BALLOON_SWITCH_RIGHT,
3453     EL_BALLOON_SWITCH_UP,
3454     EL_BALLOON_SWITCH_DOWN,
3455     EL_BALLOON_SWITCH_ANY,
3456     EL_BALLOON_SWITCH_NONE,
3457     EL_LAMP,
3458     EL_TIME_ORB_FULL,
3459     EL_EMC_MAGIC_BALL_SWITCH,
3460     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3461
3462     -1
3463   };
3464
3465   static int ep_bd_element[] =
3466   {
3467     EL_EMPTY,
3468     EL_SAND,
3469     EL_WALL_SLIPPERY,
3470     EL_BD_WALL,
3471     EL_ROCK,
3472     EL_BD_ROCK,
3473     EL_BD_DIAMOND,
3474     EL_BD_MAGIC_WALL,
3475     EL_EXIT_CLOSED,
3476     EL_EXIT_OPEN,
3477     EL_STEELWALL,
3478     EL_PLAYER_1,
3479     EL_PLAYER_2,
3480     EL_PLAYER_3,
3481     EL_PLAYER_4,
3482     EL_BD_FIREFLY,
3483     EL_BD_FIREFLY_1,
3484     EL_BD_FIREFLY_2,
3485     EL_BD_FIREFLY_3,
3486     EL_BD_FIREFLY_4,
3487     EL_BD_BUTTERFLY,
3488     EL_BD_BUTTERFLY_1,
3489     EL_BD_BUTTERFLY_2,
3490     EL_BD_BUTTERFLY_3,
3491     EL_BD_BUTTERFLY_4,
3492     EL_BD_AMOEBA,
3493     EL_CHAR_QUESTION,
3494     EL_UNKNOWN,
3495
3496     -1
3497   };
3498
3499   static int ep_sp_element[] =
3500   {
3501     /* should always be valid */
3502     EL_EMPTY,
3503
3504     /* standard classic Supaplex elements */
3505     EL_SP_EMPTY,
3506     EL_SP_ZONK,
3507     EL_SP_BASE,
3508     EL_SP_MURPHY,
3509     EL_SP_INFOTRON,
3510     EL_SP_CHIP_SINGLE,
3511     EL_SP_HARDWARE_GRAY,
3512     EL_SP_EXIT_CLOSED,
3513     EL_SP_EXIT_OPEN,
3514     EL_SP_DISK_ORANGE,
3515     EL_SP_PORT_RIGHT,
3516     EL_SP_PORT_DOWN,
3517     EL_SP_PORT_LEFT,
3518     EL_SP_PORT_UP,
3519     EL_SP_GRAVITY_PORT_RIGHT,
3520     EL_SP_GRAVITY_PORT_DOWN,
3521     EL_SP_GRAVITY_PORT_LEFT,
3522     EL_SP_GRAVITY_PORT_UP,
3523     EL_SP_SNIKSNAK,
3524     EL_SP_DISK_YELLOW,
3525     EL_SP_TERMINAL,
3526     EL_SP_DISK_RED,
3527     EL_SP_PORT_VERTICAL,
3528     EL_SP_PORT_HORIZONTAL,
3529     EL_SP_PORT_ANY,
3530     EL_SP_ELECTRON,
3531     EL_SP_BUGGY_BASE,
3532     EL_SP_CHIP_LEFT,
3533     EL_SP_CHIP_RIGHT,
3534     EL_SP_HARDWARE_BASE_1,
3535     EL_SP_HARDWARE_GREEN,
3536     EL_SP_HARDWARE_BLUE,
3537     EL_SP_HARDWARE_RED,
3538     EL_SP_HARDWARE_YELLOW,
3539     EL_SP_HARDWARE_BASE_2,
3540     EL_SP_HARDWARE_BASE_3,
3541     EL_SP_HARDWARE_BASE_4,
3542     EL_SP_HARDWARE_BASE_5,
3543     EL_SP_HARDWARE_BASE_6,
3544     EL_SP_CHIP_TOP,
3545     EL_SP_CHIP_BOTTOM,
3546
3547     /* additional elements that appeared in newer Supaplex levels */
3548     EL_INVISIBLE_WALL,
3549
3550     /* additional gravity port elements (not switching, but setting gravity) */
3551     EL_SP_GRAVITY_ON_PORT_LEFT,
3552     EL_SP_GRAVITY_ON_PORT_RIGHT,
3553     EL_SP_GRAVITY_ON_PORT_UP,
3554     EL_SP_GRAVITY_ON_PORT_DOWN,
3555     EL_SP_GRAVITY_OFF_PORT_LEFT,
3556     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3557     EL_SP_GRAVITY_OFF_PORT_UP,
3558     EL_SP_GRAVITY_OFF_PORT_DOWN,
3559
3560     /* more than one Murphy in a level results in an inactive clone */
3561     EL_SP_MURPHY_CLONE,
3562
3563     /* runtime Supaplex elements */
3564     EL_SP_DISK_RED_ACTIVE,
3565     EL_SP_TERMINAL_ACTIVE,
3566     EL_SP_BUGGY_BASE_ACTIVATING,
3567     EL_SP_BUGGY_BASE_ACTIVE,
3568     EL_SP_EXIT_OPENING,
3569     EL_SP_EXIT_CLOSING,
3570
3571     -1
3572   };
3573
3574   static int ep_sb_element[] =
3575   {
3576     EL_EMPTY,
3577     EL_STEELWALL,
3578     EL_SOKOBAN_OBJECT,
3579     EL_SOKOBAN_FIELD_EMPTY,
3580     EL_SOKOBAN_FIELD_FULL,
3581     EL_SOKOBAN_FIELD_PLAYER,
3582     EL_PLAYER_1,
3583     EL_PLAYER_2,
3584     EL_PLAYER_3,
3585     EL_PLAYER_4,
3586     EL_INVISIBLE_STEELWALL,
3587
3588     -1
3589   };
3590
3591   static int ep_gem[] =
3592   {
3593     EL_BD_DIAMOND,
3594     EL_EMERALD,
3595     EL_EMERALD_YELLOW,
3596     EL_EMERALD_RED,
3597     EL_EMERALD_PURPLE,
3598     EL_DIAMOND,
3599
3600     -1
3601   };
3602
3603   static int ep_food_dark_yamyam[] =
3604   {
3605     EL_SAND,
3606     EL_BUG,
3607     EL_SPACESHIP,
3608     EL_BD_BUTTERFLY,
3609     EL_BD_FIREFLY,
3610     EL_YAMYAM,
3611     EL_ROBOT,
3612     EL_PACMAN,
3613     EL_AMOEBA_DROP,
3614     EL_AMOEBA_DEAD,
3615     EL_AMOEBA_WET,
3616     EL_AMOEBA_DRY,
3617     EL_AMOEBA_FULL,
3618     EL_BD_AMOEBA,
3619     EL_EMERALD,
3620     EL_BD_DIAMOND,
3621     EL_EMERALD_YELLOW,
3622     EL_EMERALD_RED,
3623     EL_EMERALD_PURPLE,
3624     EL_DIAMOND,
3625     EL_PEARL,
3626     EL_CRYSTAL,
3627
3628     -1
3629   };
3630
3631   static int ep_food_penguin[] =
3632   {
3633     EL_EMERALD,
3634     EL_BD_DIAMOND,
3635     EL_EMERALD_YELLOW,
3636     EL_EMERALD_RED,
3637     EL_EMERALD_PURPLE,
3638     EL_DIAMOND,
3639     EL_PEARL,
3640     EL_CRYSTAL,
3641
3642     -1
3643   };
3644
3645   static int ep_food_pig[] =
3646   {
3647     EL_EMERALD,
3648     EL_BD_DIAMOND,
3649     EL_EMERALD_YELLOW,
3650     EL_EMERALD_RED,
3651     EL_EMERALD_PURPLE,
3652     EL_DIAMOND,
3653
3654     -1
3655   };
3656
3657   static int ep_historic_wall[] =
3658   {
3659     EL_STEELWALL,
3660     EL_GATE_1,
3661     EL_GATE_2,
3662     EL_GATE_3,
3663     EL_GATE_4,
3664     EL_GATE_1_GRAY,
3665     EL_GATE_2_GRAY,
3666     EL_GATE_3_GRAY,
3667     EL_GATE_4_GRAY,
3668     EL_GATE_1_GRAY_ACTIVE,
3669     EL_GATE_2_GRAY_ACTIVE,
3670     EL_GATE_3_GRAY_ACTIVE,
3671     EL_GATE_4_GRAY_ACTIVE,
3672     EL_EM_GATE_1,
3673     EL_EM_GATE_2,
3674     EL_EM_GATE_3,
3675     EL_EM_GATE_4,
3676     EL_EM_GATE_1_GRAY,
3677     EL_EM_GATE_2_GRAY,
3678     EL_EM_GATE_3_GRAY,
3679     EL_EM_GATE_4_GRAY,
3680     EL_EM_GATE_1_GRAY_ACTIVE,
3681     EL_EM_GATE_2_GRAY_ACTIVE,
3682     EL_EM_GATE_3_GRAY_ACTIVE,
3683     EL_EM_GATE_4_GRAY_ACTIVE,
3684     EL_EXIT_CLOSED,
3685     EL_EXIT_OPENING,
3686     EL_EXIT_OPEN,
3687     EL_WALL,
3688     EL_WALL_SLIPPERY,
3689     EL_EXPANDABLE_WALL,
3690     EL_EXPANDABLE_WALL_HORIZONTAL,
3691     EL_EXPANDABLE_WALL_VERTICAL,
3692     EL_EXPANDABLE_WALL_ANY,
3693     EL_EXPANDABLE_WALL_GROWING,
3694     EL_BD_EXPANDABLE_WALL,
3695     EL_BD_WALL,
3696     EL_SP_CHIP_SINGLE,
3697     EL_SP_CHIP_LEFT,
3698     EL_SP_CHIP_RIGHT,
3699     EL_SP_CHIP_TOP,
3700     EL_SP_CHIP_BOTTOM,
3701     EL_SP_HARDWARE_GRAY,
3702     EL_SP_HARDWARE_GREEN,
3703     EL_SP_HARDWARE_BLUE,
3704     EL_SP_HARDWARE_RED,
3705     EL_SP_HARDWARE_YELLOW,
3706     EL_SP_HARDWARE_BASE_1,
3707     EL_SP_HARDWARE_BASE_2,
3708     EL_SP_HARDWARE_BASE_3,
3709     EL_SP_HARDWARE_BASE_4,
3710     EL_SP_HARDWARE_BASE_5,
3711     EL_SP_HARDWARE_BASE_6,
3712     EL_SP_TERMINAL,
3713     EL_SP_TERMINAL_ACTIVE,
3714     EL_SP_EXIT_CLOSED,
3715     EL_SP_EXIT_OPEN,
3716     EL_INVISIBLE_STEELWALL,
3717     EL_INVISIBLE_STEELWALL_ACTIVE,
3718     EL_INVISIBLE_WALL,
3719     EL_INVISIBLE_WALL_ACTIVE,
3720     EL_STEELWALL_SLIPPERY,
3721     EL_EMC_STEELWALL_1,
3722     EL_EMC_STEELWALL_2,
3723     EL_EMC_STEELWALL_3,
3724     EL_EMC_STEELWALL_4,
3725     EL_EMC_WALL_1,
3726     EL_EMC_WALL_2,
3727     EL_EMC_WALL_3,
3728     EL_EMC_WALL_4,
3729     EL_EMC_WALL_5,
3730     EL_EMC_WALL_6,
3731     EL_EMC_WALL_7,
3732     EL_EMC_WALL_8,
3733
3734     -1
3735   };
3736
3737   static int ep_historic_solid[] =
3738   {
3739     EL_WALL,
3740     EL_EXPANDABLE_WALL,
3741     EL_EXPANDABLE_WALL_HORIZONTAL,
3742     EL_EXPANDABLE_WALL_VERTICAL,
3743     EL_EXPANDABLE_WALL_ANY,
3744     EL_BD_EXPANDABLE_WALL,
3745     EL_BD_WALL,
3746     EL_WALL_SLIPPERY,
3747     EL_EXIT_CLOSED,
3748     EL_EXIT_OPENING,
3749     EL_EXIT_OPEN,
3750     EL_AMOEBA_DEAD,
3751     EL_AMOEBA_WET,
3752     EL_AMOEBA_DRY,
3753     EL_AMOEBA_FULL,
3754     EL_BD_AMOEBA,
3755     EL_QUICKSAND_EMPTY,
3756     EL_QUICKSAND_FULL,
3757     EL_QUICKSAND_FILLING,
3758     EL_QUICKSAND_EMPTYING,
3759     EL_MAGIC_WALL,
3760     EL_MAGIC_WALL_ACTIVE,
3761     EL_MAGIC_WALL_EMPTYING,
3762     EL_MAGIC_WALL_FILLING,
3763     EL_MAGIC_WALL_FULL,
3764     EL_MAGIC_WALL_DEAD,
3765     EL_BD_MAGIC_WALL,
3766     EL_BD_MAGIC_WALL_ACTIVE,
3767     EL_BD_MAGIC_WALL_EMPTYING,
3768     EL_BD_MAGIC_WALL_FULL,
3769     EL_BD_MAGIC_WALL_FILLING,
3770     EL_BD_MAGIC_WALL_DEAD,
3771     EL_GAME_OF_LIFE,
3772     EL_BIOMAZE,
3773     EL_SP_CHIP_SINGLE,
3774     EL_SP_CHIP_LEFT,
3775     EL_SP_CHIP_RIGHT,
3776     EL_SP_CHIP_TOP,
3777     EL_SP_CHIP_BOTTOM,
3778     EL_SP_TERMINAL,
3779     EL_SP_TERMINAL_ACTIVE,
3780     EL_SP_EXIT_CLOSED,
3781     EL_SP_EXIT_OPEN,
3782     EL_INVISIBLE_WALL,
3783     EL_INVISIBLE_WALL_ACTIVE,
3784     EL_SWITCHGATE_SWITCH_UP,
3785     EL_SWITCHGATE_SWITCH_DOWN,
3786     EL_DC_SWITCHGATE_SWITCH_UP,
3787     EL_DC_SWITCHGATE_SWITCH_DOWN,
3788     EL_TIMEGATE_SWITCH,
3789     EL_TIMEGATE_SWITCH_ACTIVE,
3790     EL_DC_TIMEGATE_SWITCH,
3791     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3792     EL_EMC_WALL_1,
3793     EL_EMC_WALL_2,
3794     EL_EMC_WALL_3,
3795     EL_EMC_WALL_4,
3796     EL_EMC_WALL_5,
3797     EL_EMC_WALL_6,
3798     EL_EMC_WALL_7,
3799     EL_EMC_WALL_8,
3800     EL_WALL_PEARL,
3801     EL_WALL_CRYSTAL,
3802
3803     /* the following elements are a direct copy of "indestructible" elements,
3804        except "EL_ACID", which is "indestructible", but not "solid"! */
3805 #if 0
3806     EL_ACID,
3807 #endif
3808     EL_STEELWALL,
3809     EL_ACID_POOL_TOPLEFT,
3810     EL_ACID_POOL_TOPRIGHT,
3811     EL_ACID_POOL_BOTTOMLEFT,
3812     EL_ACID_POOL_BOTTOM,
3813     EL_ACID_POOL_BOTTOMRIGHT,
3814     EL_SP_HARDWARE_GRAY,
3815     EL_SP_HARDWARE_GREEN,
3816     EL_SP_HARDWARE_BLUE,
3817     EL_SP_HARDWARE_RED,
3818     EL_SP_HARDWARE_YELLOW,
3819     EL_SP_HARDWARE_BASE_1,
3820     EL_SP_HARDWARE_BASE_2,
3821     EL_SP_HARDWARE_BASE_3,
3822     EL_SP_HARDWARE_BASE_4,
3823     EL_SP_HARDWARE_BASE_5,
3824     EL_SP_HARDWARE_BASE_6,
3825     EL_INVISIBLE_STEELWALL,
3826     EL_INVISIBLE_STEELWALL_ACTIVE,
3827     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3828     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3829     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3830     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3831     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3832     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3833     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3834     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3835     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3836     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3837     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3838     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3839     EL_LIGHT_SWITCH,
3840     EL_LIGHT_SWITCH_ACTIVE,
3841     EL_SIGN_EXCLAMATION,
3842     EL_SIGN_RADIOACTIVITY,
3843     EL_SIGN_STOP,
3844     EL_SIGN_WHEELCHAIR,
3845     EL_SIGN_PARKING,
3846     EL_SIGN_NO_ENTRY,
3847     EL_SIGN_UNUSED_1,
3848     EL_SIGN_GIVE_WAY,
3849     EL_SIGN_ENTRY_FORBIDDEN,
3850     EL_SIGN_EMERGENCY_EXIT,
3851     EL_SIGN_YIN_YANG,
3852     EL_SIGN_UNUSED_2,
3853     EL_SIGN_SPERMS,
3854     EL_SIGN_BULLET,
3855     EL_SIGN_HEART,
3856     EL_SIGN_CROSS,
3857     EL_SIGN_FRANKIE,
3858     EL_STEEL_EXIT_CLOSED,
3859     EL_STEEL_EXIT_OPEN,
3860     EL_DC_STEELWALL_1_LEFT,
3861     EL_DC_STEELWALL_1_RIGHT,
3862     EL_DC_STEELWALL_1_TOP,
3863     EL_DC_STEELWALL_1_BOTTOM,
3864     EL_DC_STEELWALL_1_HORIZONTAL,
3865     EL_DC_STEELWALL_1_VERTICAL,
3866     EL_DC_STEELWALL_1_TOPLEFT,
3867     EL_DC_STEELWALL_1_TOPRIGHT,
3868     EL_DC_STEELWALL_1_BOTTOMLEFT,
3869     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3870     EL_DC_STEELWALL_1_TOPLEFT_2,
3871     EL_DC_STEELWALL_1_TOPRIGHT_2,
3872     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3873     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3874     EL_DC_STEELWALL_2_LEFT,
3875     EL_DC_STEELWALL_2_RIGHT,
3876     EL_DC_STEELWALL_2_TOP,
3877     EL_DC_STEELWALL_2_BOTTOM,
3878     EL_DC_STEELWALL_2_HORIZONTAL,
3879     EL_DC_STEELWALL_2_VERTICAL,
3880     EL_DC_STEELWALL_2_MIDDLE,
3881     EL_DC_STEELWALL_2_SINGLE,
3882     EL_STEELWALL_SLIPPERY,
3883     EL_EMC_STEELWALL_1,
3884     EL_EMC_STEELWALL_2,
3885     EL_EMC_STEELWALL_3,
3886     EL_EMC_STEELWALL_4,
3887     EL_CRYSTAL,
3888     EL_GATE_1,
3889     EL_GATE_2,
3890     EL_GATE_3,
3891     EL_GATE_4,
3892     EL_GATE_1_GRAY,
3893     EL_GATE_2_GRAY,
3894     EL_GATE_3_GRAY,
3895     EL_GATE_4_GRAY,
3896     EL_GATE_1_GRAY_ACTIVE,
3897     EL_GATE_2_GRAY_ACTIVE,
3898     EL_GATE_3_GRAY_ACTIVE,
3899     EL_GATE_4_GRAY_ACTIVE,
3900     EL_EM_GATE_1,
3901     EL_EM_GATE_2,
3902     EL_EM_GATE_3,
3903     EL_EM_GATE_4,
3904     EL_EM_GATE_1_GRAY,
3905     EL_EM_GATE_2_GRAY,
3906     EL_EM_GATE_3_GRAY,
3907     EL_EM_GATE_4_GRAY,
3908     EL_EM_GATE_1_GRAY_ACTIVE,
3909     EL_EM_GATE_2_GRAY_ACTIVE,
3910     EL_EM_GATE_3_GRAY_ACTIVE,
3911     EL_EM_GATE_4_GRAY_ACTIVE,
3912     EL_SWITCHGATE_OPEN,
3913     EL_SWITCHGATE_OPENING,
3914     EL_SWITCHGATE_CLOSED,
3915     EL_SWITCHGATE_CLOSING,
3916     EL_TIMEGATE_OPEN,
3917     EL_TIMEGATE_OPENING,
3918     EL_TIMEGATE_CLOSED,
3919     EL_TIMEGATE_CLOSING,
3920     EL_TUBE_ANY,
3921     EL_TUBE_VERTICAL,
3922     EL_TUBE_HORIZONTAL,
3923     EL_TUBE_VERTICAL_LEFT,
3924     EL_TUBE_VERTICAL_RIGHT,
3925     EL_TUBE_HORIZONTAL_UP,
3926     EL_TUBE_HORIZONTAL_DOWN,
3927     EL_TUBE_LEFT_UP,
3928     EL_TUBE_LEFT_DOWN,
3929     EL_TUBE_RIGHT_UP,
3930     EL_TUBE_RIGHT_DOWN,
3931
3932     -1
3933   };
3934
3935   static int ep_classic_enemy[] =
3936   {
3937     EL_BUG,
3938     EL_SPACESHIP,
3939     EL_BD_BUTTERFLY,
3940     EL_BD_FIREFLY,
3941
3942     EL_YAMYAM,
3943     EL_DARK_YAMYAM,
3944     EL_ROBOT,
3945     EL_PACMAN,
3946     EL_SP_SNIKSNAK,
3947     EL_SP_ELECTRON,
3948
3949     -1
3950   };
3951
3952   static int ep_belt[] =
3953   {
3954     EL_CONVEYOR_BELT_1_LEFT,
3955     EL_CONVEYOR_BELT_1_MIDDLE,
3956     EL_CONVEYOR_BELT_1_RIGHT,
3957     EL_CONVEYOR_BELT_2_LEFT,
3958     EL_CONVEYOR_BELT_2_MIDDLE,
3959     EL_CONVEYOR_BELT_2_RIGHT,
3960     EL_CONVEYOR_BELT_3_LEFT,
3961     EL_CONVEYOR_BELT_3_MIDDLE,
3962     EL_CONVEYOR_BELT_3_RIGHT,
3963     EL_CONVEYOR_BELT_4_LEFT,
3964     EL_CONVEYOR_BELT_4_MIDDLE,
3965     EL_CONVEYOR_BELT_4_RIGHT,
3966
3967     -1
3968   };
3969
3970   static int ep_belt_active[] =
3971   {
3972     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3973     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3974     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3975     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3976     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3977     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3978     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3979     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3980     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3981     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3982     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3983     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3984
3985     -1
3986   };
3987
3988   static int ep_belt_switch[] =
3989   {
3990     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3991     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3992     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3993     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3994     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3995     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3996     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3997     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3998     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3999     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4000     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4001     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4002
4003     -1
4004   };
4005
4006   static int ep_tube[] =
4007   {
4008     EL_TUBE_LEFT_UP,
4009     EL_TUBE_LEFT_DOWN,
4010     EL_TUBE_RIGHT_UP,
4011     EL_TUBE_RIGHT_DOWN,
4012     EL_TUBE_HORIZONTAL,
4013     EL_TUBE_HORIZONTAL_UP,
4014     EL_TUBE_HORIZONTAL_DOWN,
4015     EL_TUBE_VERTICAL,
4016     EL_TUBE_VERTICAL_LEFT,
4017     EL_TUBE_VERTICAL_RIGHT,
4018     EL_TUBE_ANY,
4019
4020     -1
4021   };
4022
4023   static int ep_acid_pool[] =
4024   {
4025     EL_ACID_POOL_TOPLEFT,
4026     EL_ACID_POOL_TOPRIGHT,
4027     EL_ACID_POOL_BOTTOMLEFT,
4028     EL_ACID_POOL_BOTTOM,
4029     EL_ACID_POOL_BOTTOMRIGHT,
4030
4031     -1
4032   };
4033
4034   static int ep_keygate[] =
4035   {
4036     EL_GATE_1,
4037     EL_GATE_2,
4038     EL_GATE_3,
4039     EL_GATE_4,
4040     EL_GATE_1_GRAY,
4041     EL_GATE_2_GRAY,
4042     EL_GATE_3_GRAY,
4043     EL_GATE_4_GRAY,
4044     EL_GATE_1_GRAY_ACTIVE,
4045     EL_GATE_2_GRAY_ACTIVE,
4046     EL_GATE_3_GRAY_ACTIVE,
4047     EL_GATE_4_GRAY_ACTIVE,
4048     EL_EM_GATE_1,
4049     EL_EM_GATE_2,
4050     EL_EM_GATE_3,
4051     EL_EM_GATE_4,
4052     EL_EM_GATE_1_GRAY,
4053     EL_EM_GATE_2_GRAY,
4054     EL_EM_GATE_3_GRAY,
4055     EL_EM_GATE_4_GRAY,
4056     EL_EM_GATE_1_GRAY_ACTIVE,
4057     EL_EM_GATE_2_GRAY_ACTIVE,
4058     EL_EM_GATE_3_GRAY_ACTIVE,
4059     EL_EM_GATE_4_GRAY_ACTIVE,
4060     EL_EMC_GATE_5,
4061     EL_EMC_GATE_6,
4062     EL_EMC_GATE_7,
4063     EL_EMC_GATE_8,
4064     EL_EMC_GATE_5_GRAY,
4065     EL_EMC_GATE_6_GRAY,
4066     EL_EMC_GATE_7_GRAY,
4067     EL_EMC_GATE_8_GRAY,
4068     EL_EMC_GATE_5_GRAY_ACTIVE,
4069     EL_EMC_GATE_6_GRAY_ACTIVE,
4070     EL_EMC_GATE_7_GRAY_ACTIVE,
4071     EL_EMC_GATE_8_GRAY_ACTIVE,
4072     EL_DC_GATE_WHITE,
4073     EL_DC_GATE_WHITE_GRAY,
4074     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4075
4076     -1
4077   };
4078
4079   static int ep_amoeboid[] =
4080   {
4081     EL_AMOEBA_DEAD,
4082     EL_AMOEBA_WET,
4083     EL_AMOEBA_DRY,
4084     EL_AMOEBA_FULL,
4085     EL_BD_AMOEBA,
4086     EL_EMC_DRIPPER,
4087
4088     -1
4089   };
4090
4091   static int ep_amoebalive[] =
4092   {
4093     EL_AMOEBA_WET,
4094     EL_AMOEBA_DRY,
4095     EL_AMOEBA_FULL,
4096     EL_BD_AMOEBA,
4097     EL_EMC_DRIPPER,
4098
4099     -1
4100   };
4101
4102   static int ep_has_editor_content[] =
4103   {
4104     EL_PLAYER_1,
4105     EL_PLAYER_2,
4106     EL_PLAYER_3,
4107     EL_PLAYER_4,
4108     EL_SP_MURPHY,
4109     EL_YAMYAM,
4110     EL_YAMYAM_LEFT,
4111     EL_YAMYAM_RIGHT,
4112     EL_YAMYAM_UP,
4113     EL_YAMYAM_DOWN,
4114     EL_AMOEBA_WET,
4115     EL_AMOEBA_DRY,
4116     EL_AMOEBA_FULL,
4117     EL_BD_AMOEBA,
4118     EL_EMC_MAGIC_BALL,
4119     EL_EMC_ANDROID,
4120
4121     -1
4122   };
4123
4124   static int ep_can_turn_each_move[] =
4125   {
4126     /* !!! do something with this one !!! */
4127     -1
4128   };
4129
4130   static int ep_can_grow[] =
4131   {
4132     EL_BD_AMOEBA,
4133     EL_AMOEBA_DROP,
4134     EL_AMOEBA_WET,
4135     EL_AMOEBA_DRY,
4136     EL_AMOEBA_FULL,
4137     EL_GAME_OF_LIFE,
4138     EL_BIOMAZE,
4139     EL_EMC_DRIPPER,
4140
4141     -1
4142   };
4143
4144   static int ep_active_bomb[] =
4145   {
4146     EL_DYNAMITE_ACTIVE,
4147     EL_EM_DYNAMITE_ACTIVE,
4148     EL_DYNABOMB_PLAYER_1_ACTIVE,
4149     EL_DYNABOMB_PLAYER_2_ACTIVE,
4150     EL_DYNABOMB_PLAYER_3_ACTIVE,
4151     EL_DYNABOMB_PLAYER_4_ACTIVE,
4152     EL_SP_DISK_RED_ACTIVE,
4153
4154     -1
4155   };
4156
4157   static int ep_inactive[] =
4158   {
4159     EL_EMPTY,
4160     EL_SAND,
4161     EL_WALL,
4162     EL_BD_WALL,
4163     EL_WALL_SLIPPERY,
4164     EL_STEELWALL,
4165     EL_AMOEBA_DEAD,
4166     EL_QUICKSAND_EMPTY,
4167     EL_QUICKSAND_FAST_EMPTY,
4168     EL_STONEBLOCK,
4169     EL_ROBOT_WHEEL,
4170     EL_KEY_1,
4171     EL_KEY_2,
4172     EL_KEY_3,
4173     EL_KEY_4,
4174     EL_EM_KEY_1,
4175     EL_EM_KEY_2,
4176     EL_EM_KEY_3,
4177     EL_EM_KEY_4,
4178     EL_EMC_KEY_5,
4179     EL_EMC_KEY_6,
4180     EL_EMC_KEY_7,
4181     EL_EMC_KEY_8,
4182     EL_GATE_1,
4183     EL_GATE_2,
4184     EL_GATE_3,
4185     EL_GATE_4,
4186     EL_GATE_1_GRAY,
4187     EL_GATE_2_GRAY,
4188     EL_GATE_3_GRAY,
4189     EL_GATE_4_GRAY,
4190     EL_GATE_1_GRAY_ACTIVE,
4191     EL_GATE_2_GRAY_ACTIVE,
4192     EL_GATE_3_GRAY_ACTIVE,
4193     EL_GATE_4_GRAY_ACTIVE,
4194     EL_EM_GATE_1,
4195     EL_EM_GATE_2,
4196     EL_EM_GATE_3,
4197     EL_EM_GATE_4,
4198     EL_EM_GATE_1_GRAY,
4199     EL_EM_GATE_2_GRAY,
4200     EL_EM_GATE_3_GRAY,
4201     EL_EM_GATE_4_GRAY,
4202     EL_EM_GATE_1_GRAY_ACTIVE,
4203     EL_EM_GATE_2_GRAY_ACTIVE,
4204     EL_EM_GATE_3_GRAY_ACTIVE,
4205     EL_EM_GATE_4_GRAY_ACTIVE,
4206     EL_EMC_GATE_5,
4207     EL_EMC_GATE_6,
4208     EL_EMC_GATE_7,
4209     EL_EMC_GATE_8,
4210     EL_EMC_GATE_5_GRAY,
4211     EL_EMC_GATE_6_GRAY,
4212     EL_EMC_GATE_7_GRAY,
4213     EL_EMC_GATE_8_GRAY,
4214     EL_EMC_GATE_5_GRAY_ACTIVE,
4215     EL_EMC_GATE_6_GRAY_ACTIVE,
4216     EL_EMC_GATE_7_GRAY_ACTIVE,
4217     EL_EMC_GATE_8_GRAY_ACTIVE,
4218     EL_DC_GATE_WHITE,
4219     EL_DC_GATE_WHITE_GRAY,
4220     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4221     EL_DC_GATE_FAKE_GRAY,
4222     EL_DYNAMITE,
4223     EL_EM_DYNAMITE,
4224     EL_INVISIBLE_STEELWALL,
4225     EL_INVISIBLE_WALL,
4226     EL_INVISIBLE_SAND,
4227     EL_LAMP,
4228     EL_LAMP_ACTIVE,
4229     EL_WALL_EMERALD,
4230     EL_WALL_DIAMOND,
4231     EL_WALL_BD_DIAMOND,
4232     EL_WALL_EMERALD_YELLOW,
4233     EL_DYNABOMB_INCREASE_NUMBER,
4234     EL_DYNABOMB_INCREASE_SIZE,
4235     EL_DYNABOMB_INCREASE_POWER,
4236 #if 0
4237     EL_SOKOBAN_OBJECT,
4238 #endif
4239     EL_SOKOBAN_FIELD_EMPTY,
4240     EL_SOKOBAN_FIELD_FULL,
4241     EL_WALL_EMERALD_RED,
4242     EL_WALL_EMERALD_PURPLE,
4243     EL_ACID_POOL_TOPLEFT,
4244     EL_ACID_POOL_TOPRIGHT,
4245     EL_ACID_POOL_BOTTOMLEFT,
4246     EL_ACID_POOL_BOTTOM,
4247     EL_ACID_POOL_BOTTOMRIGHT,
4248     EL_MAGIC_WALL,
4249     EL_MAGIC_WALL_DEAD,
4250     EL_BD_MAGIC_WALL,
4251     EL_BD_MAGIC_WALL_DEAD,
4252     EL_DC_MAGIC_WALL,
4253     EL_DC_MAGIC_WALL_DEAD,
4254     EL_AMOEBA_TO_DIAMOND,
4255     EL_BLOCKED,
4256     EL_SP_EMPTY,
4257     EL_SP_BASE,
4258     EL_SP_PORT_RIGHT,
4259     EL_SP_PORT_DOWN,
4260     EL_SP_PORT_LEFT,
4261     EL_SP_PORT_UP,
4262     EL_SP_GRAVITY_PORT_RIGHT,
4263     EL_SP_GRAVITY_PORT_DOWN,
4264     EL_SP_GRAVITY_PORT_LEFT,
4265     EL_SP_GRAVITY_PORT_UP,
4266     EL_SP_PORT_HORIZONTAL,
4267     EL_SP_PORT_VERTICAL,
4268     EL_SP_PORT_ANY,
4269     EL_SP_DISK_RED,
4270 #if 0
4271     EL_SP_DISK_YELLOW,
4272 #endif
4273     EL_SP_CHIP_SINGLE,
4274     EL_SP_CHIP_LEFT,
4275     EL_SP_CHIP_RIGHT,
4276     EL_SP_CHIP_TOP,
4277     EL_SP_CHIP_BOTTOM,
4278     EL_SP_HARDWARE_GRAY,
4279     EL_SP_HARDWARE_GREEN,
4280     EL_SP_HARDWARE_BLUE,
4281     EL_SP_HARDWARE_RED,
4282     EL_SP_HARDWARE_YELLOW,
4283     EL_SP_HARDWARE_BASE_1,
4284     EL_SP_HARDWARE_BASE_2,
4285     EL_SP_HARDWARE_BASE_3,
4286     EL_SP_HARDWARE_BASE_4,
4287     EL_SP_HARDWARE_BASE_5,
4288     EL_SP_HARDWARE_BASE_6,
4289     EL_SP_GRAVITY_ON_PORT_LEFT,
4290     EL_SP_GRAVITY_ON_PORT_RIGHT,
4291     EL_SP_GRAVITY_ON_PORT_UP,
4292     EL_SP_GRAVITY_ON_PORT_DOWN,
4293     EL_SP_GRAVITY_OFF_PORT_LEFT,
4294     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4295     EL_SP_GRAVITY_OFF_PORT_UP,
4296     EL_SP_GRAVITY_OFF_PORT_DOWN,
4297     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4298     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4299     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4300     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4301     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4302     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4303     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4304     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4305     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4306     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4307     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4308     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4309     EL_SIGN_EXCLAMATION,
4310     EL_SIGN_RADIOACTIVITY,
4311     EL_SIGN_STOP,
4312     EL_SIGN_WHEELCHAIR,
4313     EL_SIGN_PARKING,
4314     EL_SIGN_NO_ENTRY,
4315     EL_SIGN_UNUSED_1,
4316     EL_SIGN_GIVE_WAY,
4317     EL_SIGN_ENTRY_FORBIDDEN,
4318     EL_SIGN_EMERGENCY_EXIT,
4319     EL_SIGN_YIN_YANG,
4320     EL_SIGN_UNUSED_2,
4321     EL_SIGN_SPERMS,
4322     EL_SIGN_BULLET,
4323     EL_SIGN_HEART,
4324     EL_SIGN_CROSS,
4325     EL_SIGN_FRANKIE,
4326     EL_DC_STEELWALL_1_LEFT,
4327     EL_DC_STEELWALL_1_RIGHT,
4328     EL_DC_STEELWALL_1_TOP,
4329     EL_DC_STEELWALL_1_BOTTOM,
4330     EL_DC_STEELWALL_1_HORIZONTAL,
4331     EL_DC_STEELWALL_1_VERTICAL,
4332     EL_DC_STEELWALL_1_TOPLEFT,
4333     EL_DC_STEELWALL_1_TOPRIGHT,
4334     EL_DC_STEELWALL_1_BOTTOMLEFT,
4335     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4336     EL_DC_STEELWALL_1_TOPLEFT_2,
4337     EL_DC_STEELWALL_1_TOPRIGHT_2,
4338     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4339     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4340     EL_DC_STEELWALL_2_LEFT,
4341     EL_DC_STEELWALL_2_RIGHT,
4342     EL_DC_STEELWALL_2_TOP,
4343     EL_DC_STEELWALL_2_BOTTOM,
4344     EL_DC_STEELWALL_2_HORIZONTAL,
4345     EL_DC_STEELWALL_2_VERTICAL,
4346     EL_DC_STEELWALL_2_MIDDLE,
4347     EL_DC_STEELWALL_2_SINGLE,
4348     EL_STEELWALL_SLIPPERY,
4349     EL_EMC_STEELWALL_1,
4350     EL_EMC_STEELWALL_2,
4351     EL_EMC_STEELWALL_3,
4352     EL_EMC_STEELWALL_4,
4353     EL_EMC_WALL_SLIPPERY_1,
4354     EL_EMC_WALL_SLIPPERY_2,
4355     EL_EMC_WALL_SLIPPERY_3,
4356     EL_EMC_WALL_SLIPPERY_4,
4357     EL_EMC_WALL_1,
4358     EL_EMC_WALL_2,
4359     EL_EMC_WALL_3,
4360     EL_EMC_WALL_4,
4361     EL_EMC_WALL_5,
4362     EL_EMC_WALL_6,
4363     EL_EMC_WALL_7,
4364     EL_EMC_WALL_8,
4365     EL_EMC_WALL_9,
4366     EL_EMC_WALL_10,
4367     EL_EMC_WALL_11,
4368     EL_EMC_WALL_12,
4369     EL_EMC_WALL_13,
4370     EL_EMC_WALL_14,
4371     EL_EMC_WALL_15,
4372     EL_EMC_WALL_16,
4373
4374     -1
4375   };
4376
4377   static int ep_em_slippery_wall[] =
4378   {
4379     -1
4380   };
4381
4382   static int ep_gfx_crumbled[] =
4383   {
4384     EL_SAND,
4385     EL_LANDMINE,
4386     EL_DC_LANDMINE,
4387     EL_TRAP,
4388     EL_TRAP_ACTIVE,
4389
4390     -1
4391   };
4392
4393   static int ep_editor_cascade_active[] =
4394   {
4395     EL_INTERNAL_CASCADE_BD_ACTIVE,
4396     EL_INTERNAL_CASCADE_EM_ACTIVE,
4397     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4398     EL_INTERNAL_CASCADE_RND_ACTIVE,
4399     EL_INTERNAL_CASCADE_SB_ACTIVE,
4400     EL_INTERNAL_CASCADE_SP_ACTIVE,
4401     EL_INTERNAL_CASCADE_DC_ACTIVE,
4402     EL_INTERNAL_CASCADE_DX_ACTIVE,
4403     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4404     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4405     EL_INTERNAL_CASCADE_CE_ACTIVE,
4406     EL_INTERNAL_CASCADE_GE_ACTIVE,
4407     EL_INTERNAL_CASCADE_REF_ACTIVE,
4408     EL_INTERNAL_CASCADE_USER_ACTIVE,
4409     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4410
4411     -1
4412   };
4413
4414   static int ep_editor_cascade_inactive[] =
4415   {
4416     EL_INTERNAL_CASCADE_BD,
4417     EL_INTERNAL_CASCADE_EM,
4418     EL_INTERNAL_CASCADE_EMC,
4419     EL_INTERNAL_CASCADE_RND,
4420     EL_INTERNAL_CASCADE_SB,
4421     EL_INTERNAL_CASCADE_SP,
4422     EL_INTERNAL_CASCADE_DC,
4423     EL_INTERNAL_CASCADE_DX,
4424     EL_INTERNAL_CASCADE_CHARS,
4425     EL_INTERNAL_CASCADE_STEEL_CHARS,
4426     EL_INTERNAL_CASCADE_CE,
4427     EL_INTERNAL_CASCADE_GE,
4428     EL_INTERNAL_CASCADE_REF,
4429     EL_INTERNAL_CASCADE_USER,
4430     EL_INTERNAL_CASCADE_DYNAMIC,
4431
4432     -1
4433   };
4434
4435   static int ep_obsolete[] =
4436   {
4437     EL_PLAYER_OBSOLETE,
4438     EL_KEY_OBSOLETE,
4439     EL_EM_KEY_1_FILE_OBSOLETE,
4440     EL_EM_KEY_2_FILE_OBSOLETE,
4441     EL_EM_KEY_3_FILE_OBSOLETE,
4442     EL_EM_KEY_4_FILE_OBSOLETE,
4443     EL_ENVELOPE_OBSOLETE,
4444
4445     -1
4446   };
4447
4448   static struct
4449   {
4450     int *elements;
4451     int property;
4452   } element_properties[] =
4453   {
4454     { ep_diggable,                      EP_DIGGABLE                     },
4455     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4456     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4457     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4458     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4459     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4460     { ep_slippery,                      EP_SLIPPERY                     },
4461     { ep_can_change,                    EP_CAN_CHANGE                   },
4462     { ep_can_move,                      EP_CAN_MOVE                     },
4463     { ep_can_fall,                      EP_CAN_FALL                     },
4464     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4465     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4466     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4467     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4468     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4469     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4470     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4471     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4472     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4473     { ep_passable_over,                 EP_PASSABLE_OVER                },
4474     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4475     { ep_passable_under,                EP_PASSABLE_UNDER               },
4476     { ep_droppable,                     EP_DROPPABLE                    },
4477     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4478     { ep_pushable,                      EP_PUSHABLE                     },
4479     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4480     { ep_protected,                     EP_PROTECTED                    },
4481     { ep_throwable,                     EP_THROWABLE                    },
4482     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4483     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4484
4485     { ep_player,                        EP_PLAYER                       },
4486     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4487     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4488     { ep_switchable,                    EP_SWITCHABLE                   },
4489     { ep_bd_element,                    EP_BD_ELEMENT                   },
4490     { ep_sp_element,                    EP_SP_ELEMENT                   },
4491     { ep_sb_element,                    EP_SB_ELEMENT                   },
4492     { ep_gem,                           EP_GEM                          },
4493     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4494     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4495     { ep_food_pig,                      EP_FOOD_PIG                     },
4496     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4497     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4498     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4499     { ep_belt,                          EP_BELT                         },
4500     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4501     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4502     { ep_tube,                          EP_TUBE                         },
4503     { ep_acid_pool,                     EP_ACID_POOL                    },
4504     { ep_keygate,                       EP_KEYGATE                      },
4505     { ep_amoeboid,                      EP_AMOEBOID                     },
4506     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4507     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4508     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4509     { ep_can_grow,                      EP_CAN_GROW                     },
4510     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4511     { ep_inactive,                      EP_INACTIVE                     },
4512
4513     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4514
4515     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4516
4517     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4518     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4519
4520     { ep_obsolete,                      EP_OBSOLETE                     },
4521
4522     { NULL,                             -1                              }
4523   };
4524
4525   int i, j, k;
4526
4527   /* always start with reliable default values (element has no properties) */
4528   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4529     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4530       SET_PROPERTY(i, j, FALSE);
4531
4532   /* set all base element properties from above array definitions */
4533   for (i = 0; element_properties[i].elements != NULL; i++)
4534     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4535       SET_PROPERTY((element_properties[i].elements)[j],
4536                    element_properties[i].property, TRUE);
4537
4538   /* copy properties to some elements that are only stored in level file */
4539   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4540     for (j = 0; copy_properties[j][0] != -1; j++)
4541       if (HAS_PROPERTY(copy_properties[j][0], i))
4542         for (k = 1; k <= 4; k++)
4543           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4544
4545   /* set static element properties that are not listed in array definitions */
4546   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4547     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4548 }
4549
4550 void InitElementPropertiesEngine(int engine_version)
4551 {
4552   static int no_wall_properties[] =
4553   {
4554     EP_DIGGABLE,
4555     EP_COLLECTIBLE_ONLY,
4556     EP_DONT_RUN_INTO,
4557     EP_DONT_COLLIDE_WITH,
4558     EP_CAN_MOVE,
4559     EP_CAN_FALL,
4560     EP_CAN_SMASH_PLAYER,
4561     EP_CAN_SMASH_ENEMIES,
4562     EP_CAN_SMASH_EVERYTHING,
4563     EP_PUSHABLE,
4564
4565     EP_PLAYER,
4566     EP_GEM,
4567     EP_FOOD_DARK_YAMYAM,
4568     EP_FOOD_PENGUIN,
4569     EP_BELT,
4570     EP_BELT_ACTIVE,
4571     EP_TUBE,
4572     EP_AMOEBOID,
4573     EP_AMOEBALIVE,
4574     EP_ACTIVE_BOMB,
4575
4576     EP_ACCESSIBLE,
4577
4578     -1
4579   };
4580
4581   int i, j;
4582
4583   /* important: after initialization in InitElementPropertiesStatic(), the
4584      elements are not again initialized to a default value; therefore all
4585      changes have to make sure that they leave the element with a defined
4586      property (which means that conditional property changes must be set to
4587      a reliable default value before) */
4588
4589   /* resolve group elements */
4590   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4591     ResolveGroupElement(EL_GROUP_START + i);
4592
4593   /* set all special, combined or engine dependent element properties */
4594   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4595   {
4596     /* ---------- INACTIVE ------------------------------------------------- */
4597     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4598                                    i <= EL_CHAR_END) ||
4599                                   (i >= EL_STEEL_CHAR_START &&
4600                                    i <= EL_STEEL_CHAR_END)));
4601
4602     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4603     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4604                                   IS_WALKABLE_INSIDE(i) ||
4605                                   IS_WALKABLE_UNDER(i)));
4606
4607     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4608                                   IS_PASSABLE_INSIDE(i) ||
4609                                   IS_PASSABLE_UNDER(i)));
4610
4611     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4612                                          IS_PASSABLE_OVER(i)));
4613
4614     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4615                                            IS_PASSABLE_INSIDE(i)));
4616
4617     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4618                                           IS_PASSABLE_UNDER(i)));
4619
4620     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4621                                     IS_PASSABLE(i)));
4622
4623     /* ---------- COLLECTIBLE ---------------------------------------------- */
4624     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4625                                      IS_DROPPABLE(i) ||
4626                                      IS_THROWABLE(i)));
4627
4628     /* ---------- SNAPPABLE ------------------------------------------------ */
4629     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4630                                    IS_COLLECTIBLE(i) ||
4631                                    IS_SWITCHABLE(i) ||
4632                                    i == EL_BD_ROCK));
4633
4634     /* ---------- WALL ----------------------------------------------------- */
4635     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
4636
4637     for (j = 0; no_wall_properties[j] != -1; j++)
4638       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4639           i >= EL_FIRST_RUNTIME_UNREAL)
4640         SET_PROPERTY(i, EP_WALL, FALSE);
4641
4642     if (IS_HISTORIC_WALL(i))
4643       SET_PROPERTY(i, EP_WALL, TRUE);
4644
4645     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4646     if (engine_version < VERSION_IDENT(2,2,0,0))
4647       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4648     else
4649       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4650                                              !IS_DIGGABLE(i) &&
4651                                              !IS_COLLECTIBLE(i)));
4652
4653     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4654     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4655       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4656     else
4657       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4658                                             IS_INDESTRUCTIBLE(i)));
4659
4660     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4661     if (i == EL_FLAMES)
4662       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4663     else if (engine_version < VERSION_IDENT(2,2,0,0))
4664       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4665     else
4666       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4667                                            (!IS_WALKABLE(i) ||
4668                                             IS_PROTECTED(i))));
4669
4670     if (IS_CUSTOM_ELEMENT(i))
4671     {
4672       /* these are additional properties which are initially false when set */
4673
4674       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4675       if (DONT_TOUCH(i))
4676         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4677       if (DONT_COLLIDE_WITH(i))
4678         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4679
4680       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4681       if (CAN_SMASH_EVERYTHING(i))
4682         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4683       if (CAN_SMASH_ENEMIES(i))
4684         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4685     }
4686
4687     /* ---------- CAN_SMASH ------------------------------------------------ */
4688     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4689                                    CAN_SMASH_ENEMIES(i) ||
4690                                    CAN_SMASH_EVERYTHING(i)));
4691
4692     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4693     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4694                                              EXPLODES_BY_FIRE(i)));
4695
4696     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4697     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4698                                              EXPLODES_SMASHED(i)));
4699
4700     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4701     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4702                                             EXPLODES_IMPACT(i)));
4703
4704     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4705     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4706
4707     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4708     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4709                                                   i == EL_BLACK_ORB));
4710
4711     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4712     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4713                                               CAN_MOVE(i) ||
4714                                               IS_CUSTOM_ELEMENT(i)));
4715
4716     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4717     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4718                                                  i == EL_SP_ELECTRON));
4719
4720     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4721     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4722       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4723                    getMoveIntoAcidProperty(&level, i));
4724
4725     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4726     if (MAYBE_DONT_COLLIDE_WITH(i))
4727       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4728                    getDontCollideWithProperty(&level, i));
4729
4730     /* ---------- SP_PORT -------------------------------------------------- */
4731     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4732                                  IS_PASSABLE_INSIDE(i)));
4733
4734     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4735     for (j = 0; j < level.num_android_clone_elements; j++)
4736       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4737                    (i != EL_EMPTY &&
4738                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4739
4740     /* ---------- CAN_CHANGE ----------------------------------------------- */
4741     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
4742     for (j = 0; j < element_info[i].num_change_pages; j++)
4743       if (element_info[i].change_page[j].can_change)
4744         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4745
4746     /* ---------- HAS_ACTION ----------------------------------------------- */
4747     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
4748     for (j = 0; j < element_info[i].num_change_pages; j++)
4749       if (element_info[i].change_page[j].has_action)
4750         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4751
4752     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4753     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4754                                                   HAS_ACTION(i)));
4755
4756     /* ---------- GFX_CRUMBLED --------------------------------------------- */
4757 #if 1
4758     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4759                  element_info[i].crumbled[ACTION_DEFAULT] !=
4760                  element_info[i].graphic[ACTION_DEFAULT]);
4761 #else
4762     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4763     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4764                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4765 #endif
4766
4767     /* ---------- EDITOR_CASCADE ------------------------------------------- */
4768     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4769                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4770   }
4771
4772   /* dynamically adjust element properties according to game engine version */
4773   {
4774     static int ep_em_slippery_wall[] =
4775     {
4776       EL_WALL,
4777       EL_STEELWALL,
4778       EL_EXPANDABLE_WALL,
4779       EL_EXPANDABLE_WALL_HORIZONTAL,
4780       EL_EXPANDABLE_WALL_VERTICAL,
4781       EL_EXPANDABLE_WALL_ANY,
4782       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4783       EL_EXPANDABLE_STEELWALL_VERTICAL,
4784       EL_EXPANDABLE_STEELWALL_ANY,
4785       EL_EXPANDABLE_STEELWALL_GROWING,
4786       -1
4787     };
4788
4789     /* special EM style gems behaviour */
4790     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4791       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4792                    level.em_slippery_gems);
4793
4794     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4795     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4796                  (level.em_slippery_gems &&
4797                   engine_version > VERSION_IDENT(2,0,1,0)));
4798   }
4799
4800   /* this is needed because some graphics depend on element properties */
4801   if (game_status == GAME_MODE_PLAYING)
4802     InitElementGraphicInfo();
4803 }
4804
4805 void InitElementPropertiesAfterLoading(int engine_version)
4806 {
4807   int i;
4808
4809   /* set some other uninitialized values of custom elements in older levels */
4810   if (engine_version < VERSION_IDENT(3,1,0,0))
4811   {
4812     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4813     {
4814       int element = EL_CUSTOM_START + i;
4815
4816       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4817
4818       element_info[element].explosion_delay = 17;
4819       element_info[element].ignition_delay = 8;
4820     }
4821   }
4822 }
4823
4824 static void InitGlobal()
4825 {
4826   int graphic;
4827   int i;
4828
4829   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4830   {
4831     /* check if element_name_info entry defined for each element in "main.h" */
4832     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4833       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4834
4835     element_info[i].token_name = element_name_info[i].token_name;
4836     element_info[i].class_name = element_name_info[i].class_name;
4837     element_info[i].editor_description= element_name_info[i].editor_description;
4838
4839 #if 0
4840     printf("%04d: %s\n", i, element_name_info[i].token_name);
4841 #endif
4842   }
4843
4844   /* create hash from image config list */
4845   image_config_hash = newSetupFileHash();
4846   for (i = 0; image_config[i].token != NULL; i++)
4847     setHashEntry(image_config_hash,
4848                  image_config[i].token,
4849                  image_config[i].value);
4850
4851   /* create hash from element token list */
4852   element_token_hash = newSetupFileHash();
4853   for (i = 0; element_name_info[i].token_name != NULL; i++)
4854     setHashEntry(element_token_hash,
4855                  element_name_info[i].token_name,
4856                  int2str(i, 0));
4857
4858   /* create hash from graphic token list */
4859   graphic_token_hash = newSetupFileHash();
4860   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4861     if (strSuffix(image_config[i].value, ".pcx") ||
4862         strSuffix(image_config[i].value, ".wav") ||
4863         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4864       setHashEntry(graphic_token_hash,
4865                    image_config[i].token,
4866                    int2str(graphic++, 0));
4867
4868   /* create hash from font token list */
4869   font_token_hash = newSetupFileHash();
4870   for (i = 0; font_info[i].token_name != NULL; i++)
4871     setHashEntry(font_token_hash,
4872                  font_info[i].token_name,
4873                  int2str(i, 0));
4874
4875   /* always start with reliable default values (all elements) */
4876   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4877     ActiveElement[i] = i;
4878
4879   /* now add all entries that have an active state (active elements) */
4880   for (i = 0; element_with_active_state[i].element != -1; i++)
4881   {
4882     int element = element_with_active_state[i].element;
4883     int element_active = element_with_active_state[i].element_active;
4884
4885     ActiveElement[element] = element_active;
4886   }
4887
4888   /* always start with reliable default values (all buttons) */
4889   for (i = 0; i < NUM_IMAGE_FILES; i++)
4890     ActiveButton[i] = i;
4891
4892   /* now add all entries that have an active state (active buttons) */
4893   for (i = 0; button_with_active_state[i].button != -1; i++)
4894   {
4895     int button = button_with_active_state[i].button;
4896     int button_active = button_with_active_state[i].button_active;
4897
4898     ActiveButton[button] = button_active;
4899   }
4900
4901   /* always start with reliable default values (all fonts) */
4902   for (i = 0; i < NUM_FONTS; i++)
4903     ActiveFont[i] = i;
4904
4905   /* now add all entries that have an active state (active fonts) */
4906   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4907   {
4908     int font = font_with_active_state[i].font_nr;
4909     int font_active = font_with_active_state[i].font_nr_active;
4910
4911     ActiveFont[font] = font_active;
4912   }
4913
4914   global.autoplay_leveldir = NULL;
4915   global.convert_leveldir = NULL;
4916
4917   global.frames_per_second = 0;
4918   global.fps_slowdown = FALSE;
4919   global.fps_slowdown_factor = 1;
4920
4921   global.border_status = GAME_MODE_MAIN;
4922 #if 0
4923   global.fading_status = GAME_MODE_MAIN;
4924   global.fading_type = TYPE_ENTER_MENU;
4925 #endif
4926 }
4927
4928 void Execute_Command(char *command)
4929 {
4930   int i;
4931
4932   if (strEqual(command, "print graphicsinfo.conf"))
4933   {
4934     printf("# You can configure additional/alternative image files here.\n");
4935     printf("# (The entries below are default and therefore commented out.)\n");
4936     printf("\n");
4937     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4938     printf("\n");
4939     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4940     printf("\n");
4941
4942     for (i = 0; image_config[i].token != NULL; i++)
4943       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4944                                               image_config[i].value));
4945
4946     exit(0);
4947   }
4948   else if (strEqual(command, "print soundsinfo.conf"))
4949   {
4950     printf("# You can configure additional/alternative sound files here.\n");
4951     printf("# (The entries below are default and therefore commented out.)\n");
4952     printf("\n");
4953     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4954     printf("\n");
4955     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4956     printf("\n");
4957
4958     for (i = 0; sound_config[i].token != NULL; i++)
4959       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4960                                               sound_config[i].value));
4961
4962     exit(0);
4963   }
4964   else if (strEqual(command, "print musicinfo.conf"))
4965   {
4966     printf("# You can configure additional/alternative music files here.\n");
4967     printf("# (The entries below are default and therefore commented out.)\n");
4968     printf("\n");
4969     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4970     printf("\n");
4971     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4972     printf("\n");
4973
4974     for (i = 0; music_config[i].token != NULL; i++)
4975       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4976                                               music_config[i].value));
4977
4978     exit(0);
4979   }
4980   else if (strEqual(command, "print editorsetup.conf"))
4981   {
4982     printf("# You can configure your personal editor element list here.\n");
4983     printf("# (The entries below are default and therefore commented out.)\n");
4984     printf("\n");
4985
4986     /* this is needed to be able to check element list for cascade elements */
4987     InitElementPropertiesStatic();
4988     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4989
4990     PrintEditorElementList();
4991
4992     exit(0);
4993   }
4994   else if (strEqual(command, "print helpanim.conf"))
4995   {
4996     printf("# You can configure different element help animations here.\n");
4997     printf("# (The entries below are default and therefore commented out.)\n");
4998     printf("\n");
4999
5000     for (i = 0; helpanim_config[i].token != NULL; i++)
5001     {
5002       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5003                                               helpanim_config[i].value));
5004
5005       if (strEqual(helpanim_config[i].token, "end"))
5006         printf("#\n");
5007     }
5008
5009     exit(0);
5010   }
5011   else if (strEqual(command, "print helptext.conf"))
5012   {
5013     printf("# You can configure different element help text here.\n");
5014     printf("# (The entries below are default and therefore commented out.)\n");
5015     printf("\n");
5016
5017     for (i = 0; helptext_config[i].token != NULL; i++)
5018       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5019                                               helptext_config[i].value));
5020
5021     exit(0);
5022   }
5023   else if (strncmp(command, "dump level ", 11) == 0)
5024   {
5025     char *filename = &command[11];
5026
5027     if (!fileExists(filename))
5028       Error(ERR_EXIT, "cannot open file '%s'", filename);
5029
5030     LoadLevelFromFilename(&level, filename);
5031     DumpLevel(&level);
5032
5033     exit(0);
5034   }
5035   else if (strncmp(command, "dump tape ", 10) == 0)
5036   {
5037     char *filename = &command[10];
5038
5039     if (!fileExists(filename))
5040       Error(ERR_EXIT, "cannot open file '%s'", filename);
5041
5042     LoadTapeFromFilename(filename);
5043     DumpTape(&tape);
5044
5045     exit(0);
5046   }
5047   else if (strncmp(command, "autoplay ", 9) == 0)
5048   {
5049     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
5050
5051     while (*str_ptr != '\0')                    /* continue parsing string */
5052     {
5053       /* cut leading whitespace from string, replace it by string terminator */
5054       while (*str_ptr == ' ' || *str_ptr == '\t')
5055         *str_ptr++ = '\0';
5056
5057       if (*str_ptr == '\0')                     /* end of string reached */
5058         break;
5059
5060       if (global.autoplay_leveldir == NULL)     /* read level set string */
5061       {
5062         global.autoplay_leveldir = str_ptr;
5063         global.autoplay_all = TRUE;             /* default: play all tapes */
5064
5065         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5066           global.autoplay_level[i] = FALSE;
5067       }
5068       else                                      /* read level number string */
5069       {
5070         int level_nr = atoi(str_ptr);           /* get level_nr value */
5071
5072         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5073           global.autoplay_level[level_nr] = TRUE;
5074
5075         global.autoplay_all = FALSE;
5076       }
5077
5078       /* advance string pointer to the next whitespace (or end of string) */
5079       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5080         str_ptr++;
5081     }
5082   }
5083   else if (strncmp(command, "convert ", 8) == 0)
5084   {
5085     char *str_copy = getStringCopy(&command[8]);
5086     char *str_ptr = strchr(str_copy, ' ');
5087
5088     global.convert_leveldir = str_copy;
5089     global.convert_level_nr = -1;
5090
5091     if (str_ptr != NULL)                        /* level number follows */
5092     {
5093       *str_ptr++ = '\0';                        /* terminate leveldir string */
5094       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
5095     }
5096   }
5097
5098 #if DEBUG
5099 #if defined(TARGET_SDL)
5100   else if (strEqual(command, "SDL_ListModes"))
5101   {
5102     SDL_Rect **modes;
5103     int i;
5104
5105     SDL_Init(SDL_INIT_VIDEO);
5106
5107     /* get available fullscreen/hardware modes */
5108     modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
5109
5110     /* check if there are any modes available */
5111     if (modes == NULL)
5112     {
5113       printf("No modes available!\n");
5114
5115       exit(-1);
5116     }
5117
5118     /* check if our resolution is restricted */
5119     if (modes == (SDL_Rect **)-1)
5120     {
5121       printf("All resolutions available.\n");
5122     }
5123     else
5124     {
5125       printf("Available Modes:\n");
5126
5127       for(i = 0; modes[i]; i++)
5128         printf("  %d x %d\n", modes[i]->w, modes[i]->h);
5129     }
5130
5131     exit(0);
5132   }
5133 #endif
5134 #endif
5135
5136   else
5137   {
5138     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5139   }
5140 }
5141
5142 static void InitSetup()
5143 {
5144   LoadSetup();                                  /* global setup info */
5145
5146   /* set some options from setup file */
5147
5148   if (setup.options.verbose)
5149     options.verbose = TRUE;
5150 }
5151
5152 static void InitGameInfo()
5153 {
5154   game.restart_level = FALSE;
5155 }
5156
5157 static void InitPlayerInfo()
5158 {
5159   int i;
5160
5161   /* choose default local player */
5162   local_player = &stored_player[0];
5163
5164   for (i = 0; i < MAX_PLAYERS; i++)
5165     stored_player[i].connected = FALSE;
5166
5167   local_player->connected = TRUE;
5168 }
5169
5170 static void InitArtworkInfo()
5171 {
5172   LoadArtworkInfo();
5173 }
5174
5175 static char *get_string_in_brackets(char *string)
5176 {
5177   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5178
5179   sprintf(string_in_brackets, "[%s]", string);
5180
5181   return string_in_brackets;
5182 }
5183
5184 static char *get_level_id_suffix(int id_nr)
5185 {
5186   char *id_suffix = checked_malloc(1 + 3 + 1);
5187
5188   if (id_nr < 0 || id_nr > 999)
5189     id_nr = 0;
5190
5191   sprintf(id_suffix, ".%03d", id_nr);
5192
5193   return id_suffix;
5194 }
5195
5196 #if 0
5197 static char *get_element_class_token(int element)
5198 {
5199   char *element_class_name = element_info[element].class_name;
5200   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
5201
5202   sprintf(element_class_token, "[%s]", element_class_name);
5203
5204   return element_class_token;
5205 }
5206
5207 static char *get_action_class_token(int action)
5208 {
5209   char *action_class_name = &element_action_info[action].suffix[1];
5210   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
5211
5212   sprintf(action_class_token, "[%s]", action_class_name);
5213
5214   return action_class_token;
5215 }
5216 #endif
5217
5218 static void InitArtworkConfig()
5219 {
5220   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
5221   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
5222   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
5223   static char *action_id_suffix[NUM_ACTIONS + 1];
5224   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5225   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5226   static char *level_id_suffix[MAX_LEVELS + 1];
5227   static char *dummy[1] = { NULL };
5228   static char *ignore_generic_tokens[] =
5229   {
5230     "name",
5231     "sort_priority",
5232     NULL
5233   };
5234   static char **ignore_image_tokens;
5235   static char **ignore_sound_tokens;
5236   static char **ignore_music_tokens;
5237   int num_ignore_generic_tokens;
5238   int num_ignore_image_tokens;
5239   int num_ignore_sound_tokens;
5240   int num_ignore_music_tokens;
5241   int i;
5242
5243   /* dynamically determine list of generic tokens to be ignored */
5244   num_ignore_generic_tokens = 0;
5245   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5246     num_ignore_generic_tokens++;
5247
5248   /* dynamically determine list of image tokens to be ignored */
5249   num_ignore_image_tokens = num_ignore_generic_tokens;
5250   for (i = 0; image_config_vars[i].token != NULL; i++)
5251     num_ignore_image_tokens++;
5252   ignore_image_tokens =
5253     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5254   for (i = 0; i < num_ignore_generic_tokens; i++)
5255     ignore_image_tokens[i] = ignore_generic_tokens[i];
5256   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5257     ignore_image_tokens[num_ignore_generic_tokens + i] =
5258       image_config_vars[i].token;
5259   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5260
5261   /* dynamically determine list of sound tokens to be ignored */
5262   num_ignore_sound_tokens = num_ignore_generic_tokens;
5263   ignore_sound_tokens =
5264     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5265   for (i = 0; i < num_ignore_generic_tokens; i++)
5266     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5267   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5268
5269   /* dynamically determine list of music tokens to be ignored */
5270   num_ignore_music_tokens = num_ignore_generic_tokens;
5271   ignore_music_tokens =
5272     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5273   for (i = 0; i < num_ignore_generic_tokens; i++)
5274     ignore_music_tokens[i] = ignore_generic_tokens[i];
5275   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5276
5277   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5278     image_id_prefix[i] = element_info[i].token_name;
5279   for (i = 0; i < NUM_FONTS; i++)
5280     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5281   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
5282
5283   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5284     sound_id_prefix[i] = element_info[i].token_name;
5285   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5286     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5287       get_string_in_brackets(element_info[i].class_name);
5288   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
5289
5290   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5291     music_id_prefix[i] = music_prefix_info[i].prefix;
5292   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5293
5294   for (i = 0; i < NUM_ACTIONS; i++)
5295     action_id_suffix[i] = element_action_info[i].suffix;
5296   action_id_suffix[NUM_ACTIONS] = NULL;
5297
5298   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5299     direction_id_suffix[i] = element_direction_info[i].suffix;
5300   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5301
5302   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5303     special_id_suffix[i] = special_suffix_info[i].suffix;
5304   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5305
5306   for (i = 0; i < MAX_LEVELS; i++)
5307     level_id_suffix[i] = get_level_id_suffix(i);
5308   level_id_suffix[MAX_LEVELS] = NULL;
5309
5310   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5311                 image_id_prefix, action_id_suffix, direction_id_suffix,
5312                 special_id_suffix, ignore_image_tokens);
5313   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5314                 sound_id_prefix, action_id_suffix, dummy,
5315                 special_id_suffix, ignore_sound_tokens);
5316   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5317                 music_id_prefix, special_id_suffix, level_id_suffix,
5318                 dummy, ignore_music_tokens);
5319 }
5320
5321 static void InitMixer()
5322 {
5323   OpenAudio();
5324   StartMixer();
5325 }
5326
5327 void InitGfx()
5328 {
5329   char *filename_font_initial = NULL;
5330   char *filename_anim_initial = NULL;
5331   Bitmap *bitmap_font_initial = NULL;
5332   int font_height;
5333   int i, j;
5334
5335   /* determine settings for initial font (for displaying startup messages) */
5336   for (i = 0; image_config[i].token != NULL; i++)
5337   {
5338     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5339     {
5340       char font_token[128];
5341       int len_font_token;
5342
5343       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5344       len_font_token = strlen(font_token);
5345
5346       if (strEqual(image_config[i].token, font_token))
5347         filename_font_initial = image_config[i].value;
5348       else if (strlen(image_config[i].token) > len_font_token &&
5349                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5350       {
5351         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5352           font_initial[j].src_x = atoi(image_config[i].value);
5353         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5354           font_initial[j].src_y = atoi(image_config[i].value);
5355         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5356           font_initial[j].width = atoi(image_config[i].value);
5357         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5358           font_initial[j].height = atoi(image_config[i].value);
5359       }
5360     }
5361   }
5362
5363   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5364   {
5365     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5366     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5367   }
5368
5369   if (filename_font_initial == NULL)    /* should not happen */
5370     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5371
5372   /* create additional image buffers for double-buffering and cross-fading */
5373   bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5374   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
5375   bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
5376   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
5377
5378   /* initialize screen properties */
5379   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5380                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5381                    bitmap_db_field);
5382   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5383   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5384   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5385
5386   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5387
5388   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5389     font_initial[j].bitmap = bitmap_font_initial;
5390
5391   InitFontGraphicInfo();
5392
5393   font_height = getFontHeight(FC_RED);
5394
5395 #if 1
5396   DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
5397 #else
5398   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5399 #endif
5400   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
5401   DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
5402
5403   DrawInitText("Loading graphics", 120, FC_GREEN);
5404
5405 #if 1
5406 #if 1
5407   /* initialize busy animation with default values */
5408   int parameter[NUM_GFX_ARGS];
5409   for (i = 0; i < NUM_GFX_ARGS; i++)
5410     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5411                                                image_config_suffix[i].token,
5412                                                image_config_suffix[i].type);
5413 #if 0
5414   for (i = 0; i < NUM_GFX_ARGS; i++)
5415     printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
5416 #endif
5417 #endif
5418
5419   /* determine settings for busy animation (when displaying startup messages) */
5420   for (i = 0; image_config[i].token != NULL; i++)
5421   {
5422     char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5423     int len_anim_token = strlen(anim_token);
5424
5425     if (strEqual(image_config[i].token, anim_token))
5426       filename_anim_initial = image_config[i].value;
5427     else if (strlen(image_config[i].token) > len_anim_token &&
5428              strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5429     {
5430 #if 1
5431       for (j = 0; image_config_suffix[j].token != NULL; j++)
5432       {
5433         if (strEqual(&image_config[i].token[len_anim_token],
5434                      image_config_suffix[j].token))
5435           parameter[j] =
5436             get_graphic_parameter_value(image_config[i].value,
5437                                         image_config_suffix[j].token,
5438                                         image_config_suffix[j].type);
5439       }
5440 #else
5441       if (strEqual(&image_config[i].token[len_anim_token], ".x"))
5442         anim_initial.src_x = atoi(image_config[i].value);
5443       else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
5444         anim_initial.src_y = atoi(image_config[i].value);
5445       else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
5446         anim_initial.width = atoi(image_config[i].value);
5447       else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
5448         anim_initial.height = atoi(image_config[i].value);
5449       else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
5450         anim_initial.anim_frames = atoi(image_config[i].value);
5451       else if (strEqual(&image_config[i].token[len_anim_token],
5452                         ".frames_per_line"))
5453         anim_initial.anim_frames_per_line = atoi(image_config[i].value);
5454       else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
5455         anim_initial.anim_delay = atoi(image_config[i].value);
5456 #endif
5457     }
5458   }
5459
5460   set_graphic_parameters_ext(0, &anim_initial, parameter, NULL);
5461
5462   if (filename_anim_initial == NULL)    /* should not happen */
5463     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5464
5465   anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
5466
5467   init.busy.width  = anim_initial.width;
5468   init.busy.height = anim_initial.height;
5469
5470   InitMenuDesignSettings_Static();
5471   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5472 #endif
5473 }
5474
5475 void RedrawBackground()
5476 {
5477   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
5478              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
5479
5480   redraw_mask = REDRAW_ALL;
5481 }
5482
5483 void InitGfxBackground()
5484 {
5485   int x, y;
5486
5487   fieldbuffer = bitmap_db_field;
5488   SetDrawtoField(DRAW_BACKBUFFER);
5489
5490 #if 1
5491   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5492 #else
5493   RedrawBackground();
5494
5495   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
5496   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
5497 #endif
5498
5499   for (x = 0; x < MAX_BUF_XSIZE; x++)
5500     for (y = 0; y < MAX_BUF_YSIZE; y++)
5501       redraw[x][y] = 0;
5502   redraw_tiles = 0;
5503   redraw_mask = REDRAW_ALL;
5504 }
5505
5506 static void InitLevelInfo()
5507 {
5508   LoadLevelInfo();                              /* global level info */
5509   LoadLevelSetup_LastSeries();                  /* last played series info */
5510   LoadLevelSetup_SeriesInfo();                  /* last played level info */
5511 }
5512
5513 void InitLevelArtworkInfo()
5514 {
5515   LoadLevelArtworkInfo();
5516 }
5517
5518 static void InitImages()
5519 {
5520   print_init_timestamp("INIT InitImages");
5521
5522   setLevelArtworkDir(artwork.gfx_first);
5523
5524 #if 0
5525   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5526          leveldir_current->identifier,
5527          artwork.gfx_current_identifier,
5528          artwork.gfx_current->identifier,
5529          leveldir_current->graphics_set,
5530          leveldir_current->graphics_path);
5531 #endif
5532
5533   UPDATE_BUSY_STATE();
5534
5535   ReloadCustomImages();
5536   print_init_timestamp("TIME ReloadCustomImages");
5537
5538   UPDATE_BUSY_STATE();
5539
5540   LoadCustomElementDescriptions();
5541   print_init_timestamp("TIME LoadCustomElementDescriptions");
5542
5543   UPDATE_BUSY_STATE();
5544
5545   LoadMenuDesignSettings();
5546   print_init_timestamp("TIME LoadMenuDesignSettings");
5547
5548   UPDATE_BUSY_STATE();
5549
5550   ReinitializeGraphics();
5551   print_init_timestamp("TIME ReinitializeGraphics");
5552
5553   UPDATE_BUSY_STATE();
5554
5555   print_init_timestamp("DONE InitImages");
5556 }
5557
5558 static void InitSound(char *identifier)
5559 {
5560   print_init_timestamp("INIT InitSound");
5561
5562   if (identifier == NULL)
5563     identifier = artwork.snd_current->identifier;
5564
5565   /* set artwork path to send it to the sound server process */
5566   setLevelArtworkDir(artwork.snd_first);
5567
5568   InitReloadCustomSounds(identifier);
5569   print_init_timestamp("TIME InitReloadCustomSounds");
5570
5571   ReinitializeSounds();
5572   print_init_timestamp("TIME ReinitializeSounds");
5573
5574   print_init_timestamp("DONE InitSound");
5575 }
5576
5577 static void InitMusic(char *identifier)
5578 {
5579   print_init_timestamp("INIT InitMusic");
5580
5581   if (identifier == NULL)
5582     identifier = artwork.mus_current->identifier;
5583
5584   /* set artwork path to send it to the sound server process */
5585   setLevelArtworkDir(artwork.mus_first);
5586
5587   InitReloadCustomMusic(identifier);
5588   print_init_timestamp("TIME InitReloadCustomMusic");
5589
5590   ReinitializeMusic();
5591   print_init_timestamp("TIME ReinitializeMusic");
5592
5593   print_init_timestamp("DONE InitMusic");
5594 }
5595
5596 void InitNetworkServer()
5597 {
5598 #if defined(NETWORK_AVALIABLE)
5599   int nr_wanted;
5600 #endif
5601
5602   if (!options.network)
5603     return;
5604
5605 #if defined(NETWORK_AVALIABLE)
5606   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5607
5608   if (!ConnectToServer(options.server_host, options.server_port))
5609     Error(ERR_EXIT, "cannot connect to network game server");
5610
5611   SendToServer_PlayerName(setup.player_name);
5612   SendToServer_ProtocolVersion();
5613
5614   if (nr_wanted)
5615     SendToServer_NrWanted(nr_wanted);
5616 #endif
5617 }
5618
5619 static char *getNewArtworkIdentifier(int type)
5620 {
5621   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5622   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5623   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5624   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5625   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5626   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
5627   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5628   char *leveldir_identifier = leveldir_current->identifier;
5629 #if 1
5630   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5631   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5632 #else
5633   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
5634 #endif
5635   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5636   char *artwork_current_identifier;
5637   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
5638
5639   /* leveldir_current may be invalid (level group, parent link) */
5640   if (!validLevelSeries(leveldir_current))
5641     return NULL;
5642
5643   /* 1st step: determine artwork set to be activated in descending order:
5644      --------------------------------------------------------------------
5645      1. setup artwork (when configured to override everything else)
5646      2. artwork set configured in "levelinfo.conf" of current level set
5647         (artwork in level directory will have priority when loading later)
5648      3. artwork in level directory (stored in artwork sub-directory)
5649      4. setup artwork (currently configured in setup menu) */
5650
5651   if (setup_override_artwork)
5652     artwork_current_identifier = setup_artwork_set;
5653   else if (leveldir_artwork_set != NULL)
5654     artwork_current_identifier = leveldir_artwork_set;
5655   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5656     artwork_current_identifier = leveldir_identifier;
5657   else
5658     artwork_current_identifier = setup_artwork_set;
5659
5660
5661   /* 2nd step: check if it is really needed to reload artwork set
5662      ------------------------------------------------------------ */
5663
5664 #if 0
5665   if (type == ARTWORK_TYPE_GRAPHICS)
5666     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
5667            artwork_new_identifier,
5668            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5669            artwork_current_identifier,
5670            leveldir_current->graphics_set,
5671            leveldir_current->identifier);
5672 #endif
5673
5674   /* ---------- reload if level set and also artwork set has changed ------- */
5675   if (leveldir_current_identifier[type] != leveldir_identifier &&
5676       (last_has_level_artwork_set[type] || has_level_artwork_set))
5677     artwork_new_identifier = artwork_current_identifier;
5678
5679   leveldir_current_identifier[type] = leveldir_identifier;
5680   last_has_level_artwork_set[type] = has_level_artwork_set;
5681
5682 #if 0
5683   if (type == ARTWORK_TYPE_GRAPHICS)
5684     printf("::: 1: '%s'\n", artwork_new_identifier);
5685 #endif
5686
5687   /* ---------- reload if "override artwork" setting has changed ----------- */
5688   if (last_override_level_artwork[type] != setup_override_artwork)
5689     artwork_new_identifier = artwork_current_identifier;
5690
5691   last_override_level_artwork[type] = setup_override_artwork;
5692
5693 #if 0
5694   if (type == ARTWORK_TYPE_GRAPHICS)
5695     printf("::: 2: '%s'\n", artwork_new_identifier);
5696 #endif
5697
5698   /* ---------- reload if current artwork identifier has changed ----------- */
5699   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5700                 artwork_current_identifier))
5701     artwork_new_identifier = artwork_current_identifier;
5702
5703   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5704
5705 #if 0
5706   if (type == ARTWORK_TYPE_GRAPHICS)
5707     printf("::: 3: '%s'\n", artwork_new_identifier);
5708 #endif
5709
5710   /* ---------- do not reload directly after starting ---------------------- */
5711   if (!initialized[type])
5712     artwork_new_identifier = NULL;
5713
5714   initialized[type] = TRUE;
5715
5716 #if 0
5717   if (type == ARTWORK_TYPE_GRAPHICS)
5718     printf("::: 4: '%s'\n", artwork_new_identifier);
5719 #endif
5720
5721 #if 0
5722   if (type == ARTWORK_TYPE_GRAPHICS)
5723     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
5724            artwork.gfx_current_identifier, artwork_current_identifier,
5725            artwork.gfx_current->identifier, leveldir_current->graphics_set,
5726            artwork_new_identifier);
5727 #endif
5728
5729   return artwork_new_identifier;
5730 }
5731
5732 void ReloadCustomArtwork(int force_reload)
5733 {
5734   char *gfx_new_identifier;
5735   char *snd_new_identifier;
5736   char *mus_new_identifier;
5737   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5738   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5739   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5740   boolean reload_needed;
5741
5742   force_reload_gfx |= AdjustGraphicsForEMC();
5743
5744   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5745   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5746   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5747
5748   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5749                    snd_new_identifier != NULL || force_reload_snd ||
5750                    mus_new_identifier != NULL || force_reload_mus);
5751
5752   if (!reload_needed)
5753     return;
5754
5755   print_init_timestamp("INIT ReloadCustomArtwork");
5756
5757   ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
5758   print_init_timestamp("TIME ClearRectangle");
5759
5760   if (gfx_new_identifier != NULL || force_reload_gfx)
5761   {
5762 #if 0
5763     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5764            artwork.gfx_current_identifier,
5765            gfx_new_identifier,
5766            artwork.gfx_current->identifier,
5767            leveldir_current->graphics_set);
5768 #endif
5769
5770     InitImages();
5771     print_init_timestamp("TIME InitImages");
5772   }
5773
5774   if (snd_new_identifier != NULL || force_reload_snd)
5775   {
5776     InitSound(snd_new_identifier);
5777     print_init_timestamp("TIME InitSound");
5778   }
5779
5780   if (mus_new_identifier != NULL || force_reload_mus)
5781   {
5782     InitMusic(mus_new_identifier);
5783     print_init_timestamp("TIME InitMusic");
5784   }
5785
5786   RedrawBackground();
5787
5788   /* force redraw of (open or closed) door graphics */
5789   SetDoorState(DOOR_OPEN_ALL);
5790   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5791
5792 #if 1
5793 #if 1
5794   FadeSetEnterScreen();
5795   // FadeSkipNextFadeOut();
5796   // FadeSetDisabled();
5797 #else
5798   FadeSkipNext();
5799 #endif
5800 #else
5801   fading = fading_none;
5802 #endif
5803
5804   print_init_timestamp("DONE ReloadCustomArtwork");
5805 }
5806
5807 void KeyboardAutoRepeatOffUnlessAutoplay()
5808 {
5809   if (global.autoplay_leveldir == NULL)
5810     KeyboardAutoRepeatOff();
5811 }
5812
5813
5814 /* ========================================================================= */
5815 /* OpenAll()                                                                 */
5816 /* ========================================================================= */
5817
5818 void OpenAll()
5819 {
5820   print_init_timestamp("INIT OpenAll");
5821
5822   InitGlobal();                 /* initialize some global variables */
5823
5824   if (options.execute_command)
5825     Execute_Command(options.execute_command);
5826
5827   if (options.serveronly)
5828   {
5829 #if defined(PLATFORM_UNIX)
5830     NetworkServer(options.server_port, options.serveronly);
5831 #else
5832     Error(ERR_WARN, "networking only supported in Unix version");
5833 #endif
5834
5835     exit(0);                    /* never reached, server loops forever */
5836   }
5837
5838   InitSetup();
5839
5840   InitGameInfo();
5841   InitPlayerInfo();
5842   InitArtworkInfo();            /* needed before loading gfx, sound & music */
5843   InitArtworkConfig();          /* needed before forking sound child process */
5844   InitMixer();
5845
5846   InitCounter();
5847
5848   InitRND(NEW_RANDOMIZE);
5849   InitSimpleRandom(NEW_RANDOMIZE);
5850
5851   InitJoysticks();
5852
5853   print_init_timestamp("TIME [pre-video]");
5854
5855   InitVideoDisplay();
5856   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5857
5858   InitEventFilter(FilterMouseMotionEvents);
5859
5860   InitElementPropertiesStatic();
5861   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5862
5863   print_init_timestamp("TIME [post-video]");
5864
5865   InitGfx();
5866
5867   print_init_timestamp("TIME InitGfx");
5868
5869   InitLevelInfo();
5870   print_init_timestamp("TIME InitLevelInfo");
5871
5872   InitLevelArtworkInfo();
5873   print_init_timestamp("TIME InitLevelArtworkInfo");
5874
5875   InitImages();                 /* needs to know current level directory */
5876   print_init_timestamp("TIME InitImages");
5877
5878   InitSound(NULL);              /* needs to know current level directory */
5879   print_init_timestamp("TIME InitSound");
5880
5881   InitMusic(NULL);              /* needs to know current level directory */
5882   print_init_timestamp("TIME InitMusic");
5883
5884   InitGfxBackground();
5885
5886 #if 1
5887   em_open_all();
5888 #endif
5889
5890   if (global.autoplay_leveldir)
5891   {
5892     AutoPlayTape();
5893     return;
5894   }
5895   else if (global.convert_leveldir)
5896   {
5897     ConvertLevels();
5898     return;
5899   }
5900
5901   game_status = GAME_MODE_MAIN;
5902
5903 #if 1
5904   FadeSetEnterScreen();
5905   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5906     FadeSkipNextFadeOut();
5907   // FadeSetDisabled();
5908 #else
5909   fading = fading_none;
5910 #endif
5911
5912   print_init_timestamp("TIME [post-artwork]");
5913
5914   print_init_timestamp("DONE OpenAll");
5915
5916   DrawMainMenu();
5917
5918   InitNetworkServer();
5919 }
5920
5921 void CloseAllAndExit(int exit_value)
5922 {
5923   StopSounds();
5924   FreeAllSounds();
5925   FreeAllMusic();
5926   CloseAudio();         /* called after freeing sounds (needed for SDL) */
5927
5928 #if 1
5929   em_close_all();
5930 #endif
5931
5932   FreeAllImages();
5933
5934 #if defined(TARGET_SDL)
5935   if (network_server)   /* terminate network server */
5936     SDL_KillThread(server_thread);
5937 #endif
5938
5939   CloseVideoDisplay();
5940   ClosePlatformDependentStuff();
5941
5942   if (exit_value != 0)
5943     NotifyUserAboutErrorFile();
5944
5945   exit(exit_value);
5946 }