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