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