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