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