rnd-20051209-1-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 InitGraphicInfo()
1071 {
1072   int fallback_graphic = IMG_CHAR_EXCLAM;
1073   int num_images = getImageListSize();
1074   int i;
1075
1076 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1077   static boolean clipmasks_initialized = FALSE;
1078   Pixmap src_pixmap;
1079   XGCValues clip_gc_values;
1080   unsigned long clip_gc_valuemask;
1081   GC copy_clipmask_gc = None;
1082 #endif
1083
1084   checked_free(graphic_info);
1085
1086   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1087
1088 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1089   if (clipmasks_initialized)
1090   {
1091     for (i = 0; i < num_images; i++)
1092     {
1093       if (graphic_info[i].clip_mask)
1094         XFreePixmap(display, graphic_info[i].clip_mask);
1095       if (graphic_info[i].clip_gc)
1096         XFreeGC(display, graphic_info[i].clip_gc);
1097
1098       graphic_info[i].clip_mask = None;
1099       graphic_info[i].clip_gc = None;
1100     }
1101   }
1102 #endif
1103
1104 #if 1
1105   /* first set all graphic paramaters ... */
1106   for (i = 0; i < num_images; i++)
1107   {
1108     set_graphic_parameters(i, i);
1109   }
1110
1111   /* ... then copy these parameters for cloned graphics */
1112   for (i = 0; i < num_images; i++)
1113   {
1114     if (graphic_info[i].clone_from != -1)
1115     {
1116       int clone_graphic = graphic_info[i].clone_from;
1117
1118       if (graphic_info[clone_graphic].clone_from != -1)
1119       {
1120         Error(ERR_RETURN_LINE, "-");
1121         Error(ERR_RETURN, "warning: error found in config file:");
1122         Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1123         Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1124         Error(ERR_RETURN,
1125               "error: cannot clone from already cloned graphic '%s'",
1126               getTokenFromImageID(clone_graphic));
1127         Error(ERR_RETURN, "custom graphic rejected for this element/action");
1128
1129         if (i == fallback_graphic)
1130           Error(ERR_EXIT, "fatal error: no fallback graphic available");
1131
1132         Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1133         Error(ERR_RETURN_LINE, "-");
1134
1135         set_graphic_parameters(i, fallback_graphic);
1136       }
1137       else
1138       {
1139         graphic_info[i] = graphic_info[clone_graphic];
1140         graphic_info[i].clone_from = clone_graphic;
1141
1142 #if 0
1143         printf("::: graphic %d ['%s'] is cloned from %d ['%s']\n",
1144                i, getTokenFromImageID(i),
1145                clone_graphic, getTokenFromImageID(clone_graphic));
1146 #endif
1147       }
1148     }
1149   }
1150 #endif
1151
1152   for (i = 0; i < num_images; i++)
1153   {
1154     Bitmap *src_bitmap;
1155     int src_x, src_y;
1156     int first_frame, last_frame;
1157     int src_bitmap_width, src_bitmap_height;
1158
1159 #if 0
1160     printf("::: image # %d: '%s' ['%s']\n",
1161            i, image->token, getTokenFromImageID(i));
1162 #endif
1163
1164 #if 0
1165     set_graphic_parameters(i, i);
1166 #endif
1167
1168     /* now check if no animation frames are outside of the loaded image */
1169
1170 #if 0
1171     if (graphic_info[i].bitmap == NULL)
1172       Error(ERR_WARN, "no bitmap for graphic %d ['%s']",
1173             i, getTokenFromImageID(i));
1174 #endif
1175
1176     if (graphic_info[i].bitmap == NULL)
1177       continue;         /* skip check for optional images that are undefined */
1178
1179 #if 1
1180     /* get final bitmap size (with scaling, but without small images) */
1181     src_bitmap_width  = graphic_info[i].src_image_width;
1182     src_bitmap_height = graphic_info[i].src_image_height;
1183 #else
1184     /* get final bitmap size (with scaling, but without small images) */
1185     src_bitmap_width  = get_scaled_graphic_width(i);
1186     src_bitmap_height = get_scaled_graphic_height(i);
1187
1188     if (graphic_info[i].clone_from != -1)
1189     {
1190       int clone_graphic = graphic_info[i].clone_from;
1191
1192       src_bitmap_width  = get_scaled_graphic_width(clone_graphic);
1193       src_bitmap_height = get_scaled_graphic_height(clone_graphic);
1194     }
1195 #endif
1196
1197     first_frame = 0;
1198     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1199     if (src_x < 0 || src_y < 0 ||
1200         src_x + TILEX > src_bitmap_width ||
1201         src_y + TILEY > src_bitmap_height)
1202     {
1203       Error(ERR_RETURN_LINE, "-");
1204       Error(ERR_RETURN, "warning: error found in config file:");
1205       Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1206       Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1207       Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1208       Error(ERR_RETURN,
1209             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1210             src_x, src_y, src_bitmap_width, src_bitmap_height);
1211       Error(ERR_RETURN, "custom graphic rejected for this element/action");
1212
1213       if (i == fallback_graphic)
1214         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1215
1216       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1217       Error(ERR_RETURN_LINE, "-");
1218
1219       set_graphic_parameters(i, fallback_graphic);
1220     }
1221
1222     last_frame = graphic_info[i].anim_frames - 1;
1223     getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1224     if (src_x < 0 || src_y < 0 ||
1225         src_x + TILEX > src_bitmap_width ||
1226         src_y + TILEY > src_bitmap_height)
1227     {
1228       Error(ERR_RETURN_LINE, "-");
1229       Error(ERR_RETURN, "warning: error found in config file:");
1230       Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1231       Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1232       Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1233       Error(ERR_RETURN,
1234             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1235             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1236       Error(ERR_RETURN, "custom graphic rejected for this element/action");
1237
1238       if (i == fallback_graphic)
1239         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1240
1241       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1242       Error(ERR_RETURN_LINE, "-");
1243
1244       set_graphic_parameters(i, fallback_graphic);
1245     }
1246
1247 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1248     /* currently we only need a tile clip mask from the first frame */
1249     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1250
1251     if (copy_clipmask_gc == None)
1252     {
1253       clip_gc_values.graphics_exposures = False;
1254       clip_gc_valuemask = GCGraphicsExposures;
1255       copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1256                                    clip_gc_valuemask, &clip_gc_values);
1257     }
1258
1259     graphic_info[i].clip_mask =
1260       XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1261
1262     src_pixmap = src_bitmap->clip_mask;
1263     XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1264               copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1265
1266     clip_gc_values.graphics_exposures = False;
1267     clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1268     clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1269
1270     graphic_info[i].clip_gc =
1271       XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1272 #endif
1273   }
1274
1275 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1276   if (copy_clipmask_gc)
1277     XFreeGC(display, copy_clipmask_gc);
1278
1279   clipmasks_initialized = TRUE;
1280 #endif
1281 }
1282
1283 static void InitElementSoundInfo()
1284 {
1285   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1286   int num_property_mappings = getSoundListPropertyMappingSize();
1287   int i, j, act;
1288
1289   /* set values to -1 to identify later as "uninitialized" values */
1290   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1291     for (act = 0; act < NUM_ACTIONS; act++)
1292       element_info[i].sound[act] = -1;
1293
1294   /* initialize element/sound mapping from static configuration */
1295   for (i = 0; element_to_sound[i].element > -1; i++)
1296   {
1297     int element      = element_to_sound[i].element;
1298     int action       = element_to_sound[i].action;
1299     int sound        = element_to_sound[i].sound;
1300     boolean is_class = element_to_sound[i].is_class;
1301
1302     if (action < 0)
1303       action = ACTION_DEFAULT;
1304
1305     if (!is_class)
1306       element_info[element].sound[action] = sound;
1307     else
1308       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1309         if (strcmp(element_info[j].class_name,
1310                    element_info[element].class_name) == 0)
1311           element_info[j].sound[action] = sound;
1312   }
1313
1314   /* initialize element class/sound mapping from dynamic configuration */
1315   for (i = 0; i < num_property_mappings; i++)
1316   {
1317     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1318     int action        = property_mapping[i].ext1_index;
1319     int sound         = property_mapping[i].artwork_index;
1320
1321     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1322       continue;
1323
1324     if (action < 0)
1325       action = ACTION_DEFAULT;
1326
1327     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1328       if (strcmp(element_info[j].class_name,
1329                  element_info[element_class].class_name) == 0)
1330         element_info[j].sound[action] = sound;
1331   }
1332
1333   /* initialize element/sound mapping from dynamic configuration */
1334   for (i = 0; i < num_property_mappings; i++)
1335   {
1336     int element = property_mapping[i].base_index;
1337     int action  = property_mapping[i].ext1_index;
1338     int sound   = property_mapping[i].artwork_index;
1339
1340     if (element >= MAX_NUM_ELEMENTS)
1341       continue;
1342
1343     if (action < 0)
1344       action = ACTION_DEFAULT;
1345
1346     element_info[element].sound[action] = sound;
1347   }
1348
1349   /* now set all '-1' values to element specific default values */
1350   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1351   {
1352     for (act = 0; act < NUM_ACTIONS; act++)
1353     {
1354       /* generic default action sound (defined by "[default]" directive) */
1355       int default_action_sound = element_info[EL_DEFAULT].sound[act];
1356
1357       /* look for special default action sound (classic game specific) */
1358       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1359         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1360       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1361         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1362       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1363         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1364
1365       /* !!! there's no such thing as a "default action sound" !!! */
1366 #if 0
1367       /* look for element specific default sound (independent from action) */
1368       if (element_info[i].sound[ACTION_DEFAULT] != -1)
1369         default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1370 #endif
1371
1372 #if 1
1373       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1374       /* !!! make this better !!! */
1375       if (i == EL_EMPTY_SPACE)
1376         default_action_sound = element_info[EL_DEFAULT].sound[act];
1377 #endif
1378
1379       /* no sound for this specific action -- use default action sound */
1380       if (element_info[i].sound[act] == -1)
1381         element_info[i].sound[act] = default_action_sound;
1382     }
1383   }
1384
1385   /* copy sound settings to some elements that are only stored in level file
1386      in native R'n'D levels, but are used by game engine in native EM levels */
1387   for (i = 0; copy_properties[i][0] != -1; i++)
1388     for (j = 1; j <= 4; j++)
1389       for (act = 0; act < NUM_ACTIONS; act++)
1390         element_info[copy_properties[i][j]].sound[act] =
1391           element_info[copy_properties[i][0]].sound[act];
1392 }
1393
1394 static void InitGameModeSoundInfo()
1395 {
1396   int i;
1397
1398   /* set values to -1 to identify later as "uninitialized" values */
1399   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1400     menu.sound[i] = -1;
1401
1402   /* initialize gamemode/sound mapping from static configuration */
1403   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1404   {
1405     int gamemode = gamemode_to_sound[i].gamemode;
1406     int sound    = gamemode_to_sound[i].sound;
1407
1408     if (gamemode < 0)
1409       gamemode = GAME_MODE_DEFAULT;
1410
1411     menu.sound[gamemode] = sound;
1412   }
1413
1414   /* now set all '-1' values to levelset specific default values */
1415   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1416     if (menu.sound[i] == -1)
1417       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1418
1419 #if 0
1420   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1421     if (menu.sound[i] != -1)
1422       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1423 #endif
1424 }
1425
1426 static void set_sound_parameters(int sound, char **parameter_raw)
1427 {
1428   int parameter[NUM_SND_ARGS];
1429   int i;
1430
1431   /* get integer values from string parameters */
1432   for (i = 0; i < NUM_SND_ARGS; i++)
1433     parameter[i] =
1434       get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
1435                           sound_config_suffix[i].type);
1436
1437   /* explicit loop mode setting in configuration overrides default value */
1438   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1439     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1440
1441   /* sound volume to change the original volume when loading the sound file */
1442   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1443
1444   /* sound priority to give certain sounds a higher or lower priority */
1445   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1446 }
1447
1448 static void InitSoundInfo()
1449 {
1450   int *sound_effect_properties;
1451   int num_sounds = getSoundListSize();
1452   int i, j;
1453
1454   checked_free(sound_info);
1455
1456   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1457   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1458
1459   /* initialize sound effect for all elements to "no sound" */
1460   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1461     for (j = 0; j < NUM_ACTIONS; j++)
1462       element_info[i].sound[j] = SND_UNDEFINED;
1463
1464   for (i = 0; i < num_sounds; i++)
1465   {
1466     struct FileInfo *sound = getSoundListEntry(i);
1467     int len_effect_text = strlen(sound->token);
1468
1469     sound_effect_properties[i] = ACTION_OTHER;
1470     sound_info[i].loop = FALSE;         /* default: play sound only once */
1471
1472 #if 0
1473     printf("::: sound %d: '%s'\n", i, sound->token);
1474 #endif
1475
1476     /* determine all loop sounds and identify certain sound classes */
1477
1478     for (j = 0; element_action_info[j].suffix; j++)
1479     {
1480       int len_action_text = strlen(element_action_info[j].suffix);
1481
1482       if (len_action_text < len_effect_text &&
1483           strcmp(&sound->token[len_effect_text - len_action_text],
1484                  element_action_info[j].suffix) == 0)
1485       {
1486         sound_effect_properties[i] = element_action_info[j].value;
1487         sound_info[i].loop = element_action_info[j].is_loop_sound;
1488
1489         break;
1490       }
1491     }
1492
1493     /* associate elements and some selected sound actions */
1494
1495     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1496     {
1497       if (element_info[j].class_name)
1498       {
1499         int len_class_text = strlen(element_info[j].class_name);
1500
1501         if (len_class_text + 1 < len_effect_text &&
1502             strncmp(sound->token,
1503                     element_info[j].class_name, len_class_text) == 0 &&
1504             sound->token[len_class_text] == '.')
1505         {
1506           int sound_action_value = sound_effect_properties[i];
1507
1508           element_info[j].sound[sound_action_value] = i;
1509         }
1510       }
1511     }
1512
1513     set_sound_parameters(i, sound->parameter);
1514   }
1515
1516   free(sound_effect_properties);
1517 }
1518
1519 static void InitGameModeMusicInfo()
1520 {
1521   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1522   int num_property_mappings = getMusicListPropertyMappingSize();
1523   int default_levelset_music = -1;
1524   int i;
1525
1526   /* set values to -1 to identify later as "uninitialized" values */
1527   for (i = 0; i < MAX_LEVELS; i++)
1528     levelset.music[i] = -1;
1529   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1530     menu.music[i] = -1;
1531
1532   /* initialize gamemode/music mapping from static configuration */
1533   for (i = 0; gamemode_to_music[i].music > -1; i++)
1534   {
1535     int gamemode = gamemode_to_music[i].gamemode;
1536     int music    = gamemode_to_music[i].music;
1537
1538 #if 0
1539     printf("::: gamemode == %d, music == %d\n", gamemode, music);
1540 #endif
1541
1542     if (gamemode < 0)
1543       gamemode = GAME_MODE_DEFAULT;
1544
1545     menu.music[gamemode] = music;
1546   }
1547
1548   /* initialize gamemode/music mapping from dynamic configuration */
1549   for (i = 0; i < num_property_mappings; i++)
1550   {
1551     int prefix   = property_mapping[i].base_index;
1552     int gamemode = property_mapping[i].ext1_index;
1553     int level    = property_mapping[i].ext2_index;
1554     int music    = property_mapping[i].artwork_index;
1555
1556 #if 0
1557     printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1558            prefix, gamemode, level, music);
1559 #endif
1560
1561     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1562       continue;
1563
1564     if (gamemode < 0)
1565       gamemode = GAME_MODE_DEFAULT;
1566
1567     /* level specific music only allowed for in-game music */
1568     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1569       gamemode = GAME_MODE_PLAYING;
1570
1571     if (level == -1)
1572     {
1573       level = 0;
1574       default_levelset_music = music;
1575     }
1576
1577     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1578       levelset.music[level] = music;
1579     if (gamemode != GAME_MODE_PLAYING)
1580       menu.music[gamemode] = music;
1581   }
1582
1583   /* now set all '-1' values to menu specific default values */
1584   /* (undefined values of "levelset.music[]" might stay at "-1" to
1585      allow dynamic selection of music files from music directory!) */
1586   for (i = 0; i < MAX_LEVELS; i++)
1587     if (levelset.music[i] == -1)
1588       levelset.music[i] = default_levelset_music;
1589   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1590     if (menu.music[i] == -1)
1591       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1592
1593 #if 0
1594   for (i = 0; i < MAX_LEVELS; i++)
1595     if (levelset.music[i] != -1)
1596       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1597   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1598     if (menu.music[i] != -1)
1599       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1600 #endif
1601 }
1602
1603 static void set_music_parameters(int music, char **parameter_raw)
1604 {
1605   int parameter[NUM_MUS_ARGS];
1606   int i;
1607
1608   /* get integer values from string parameters */
1609   for (i = 0; i < NUM_MUS_ARGS; i++)
1610     parameter[i] =
1611       get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
1612                           music_config_suffix[i].type);
1613
1614   /* explicit loop mode setting in configuration overrides default value */
1615   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1616     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1617 }
1618
1619 static void InitMusicInfo()
1620 {
1621   int num_music = getMusicListSize();
1622   int i, j;
1623
1624   checked_free(music_info);
1625
1626   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1627
1628   for (i = 0; i < num_music; i++)
1629   {
1630     struct FileInfo *music = getMusicListEntry(i);
1631     int len_music_text = strlen(music->token);
1632
1633     music_info[i].loop = TRUE;          /* default: play music in loop mode */
1634
1635     /* determine all loop music */
1636
1637     for (j = 0; music_prefix_info[j].prefix; j++)
1638     {
1639       int len_prefix_text = strlen(music_prefix_info[j].prefix);
1640
1641       if (len_prefix_text < len_music_text &&
1642           strncmp(music->token,
1643                   music_prefix_info[j].prefix, len_prefix_text) == 0)
1644       {
1645         music_info[i].loop = music_prefix_info[j].is_loop_music;
1646
1647         break;
1648       }
1649     }
1650
1651     set_music_parameters(i, music->parameter);
1652   }
1653 }
1654
1655 static void ReinitializeGraphics()
1656 {
1657   InitGraphicInfo();                    /* graphic properties mapping */
1658   InitElementGraphicInfo();             /* element game graphic mapping */
1659   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
1660
1661   InitElementSmallImages();             /* scale images to all needed sizes */
1662   InitFontGraphicInfo();                /* initialize text drawing functions */
1663
1664   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
1665
1666   SetMainBackgroundImage(IMG_BACKGROUND);
1667   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1668
1669   InitGadgets();
1670   InitToons();
1671 }
1672
1673 static void ReinitializeSounds()
1674 {
1675   InitSoundInfo();              /* sound properties mapping */
1676   InitElementSoundInfo();       /* element game sound mapping */
1677   InitGameModeSoundInfo();      /* game mode sound mapping */
1678
1679   InitPlayLevelSound();         /* internal game sound settings */
1680 }
1681
1682 static void ReinitializeMusic()
1683 {
1684   InitMusicInfo();              /* music properties mapping */
1685   InitGameModeMusicInfo();      /* game mode music mapping */
1686 }
1687
1688 static int get_special_property_bit(int element, int property_bit_nr)
1689 {
1690   struct PropertyBitInfo
1691   {
1692     int element;
1693     int bit_nr;
1694   };
1695
1696   static struct PropertyBitInfo pb_can_move_into_acid[] =
1697   {
1698     /* the player may be able fall into acid when gravity is activated */
1699     { EL_PLAYER_1,              0       },
1700     { EL_PLAYER_2,              0       },
1701     { EL_PLAYER_3,              0       },
1702     { EL_PLAYER_4,              0       },
1703     { EL_SP_MURPHY,             0       },
1704     { EL_SOKOBAN_FIELD_PLAYER,  0       },
1705
1706     /* all element that can move may be able to also move into acid */
1707     { EL_BUG,                   1       },
1708     { EL_BUG_LEFT,              1       },
1709     { EL_BUG_RIGHT,             1       },
1710     { EL_BUG_UP,                1       },
1711     { EL_BUG_DOWN,              1       },
1712     { EL_SPACESHIP,             2       },
1713     { EL_SPACESHIP_LEFT,        2       },
1714     { EL_SPACESHIP_RIGHT,       2       },
1715     { EL_SPACESHIP_UP,          2       },
1716     { EL_SPACESHIP_DOWN,        2       },
1717     { EL_BD_BUTTERFLY,          3       },
1718     { EL_BD_BUTTERFLY_LEFT,     3       },
1719     { EL_BD_BUTTERFLY_RIGHT,    3       },
1720     { EL_BD_BUTTERFLY_UP,       3       },
1721     { EL_BD_BUTTERFLY_DOWN,     3       },
1722     { EL_BD_FIREFLY,            4       },
1723     { EL_BD_FIREFLY_LEFT,       4       },
1724     { EL_BD_FIREFLY_RIGHT,      4       },
1725     { EL_BD_FIREFLY_UP,         4       },
1726     { EL_BD_FIREFLY_DOWN,       4       },
1727     { EL_YAMYAM,                5       },
1728     { EL_DARK_YAMYAM,           6       },
1729     { EL_ROBOT,                 7       },
1730     { EL_PACMAN,                8       },
1731     { EL_PACMAN_LEFT,           8       },
1732     { EL_PACMAN_RIGHT,          8       },
1733     { EL_PACMAN_UP,             8       },
1734     { EL_PACMAN_DOWN,           8       },
1735     { EL_MOLE,                  9       },
1736     { EL_MOLE_LEFT,             9       },
1737     { EL_MOLE_RIGHT,            9       },
1738     { EL_MOLE_UP,               9       },
1739     { EL_MOLE_DOWN,             9       },
1740     { EL_PENGUIN,               10      },
1741     { EL_PIG,                   11      },
1742     { EL_DRAGON,                12      },
1743     { EL_SATELLITE,             13      },
1744     { EL_SP_SNIKSNAK,           14      },
1745     { EL_SP_ELECTRON,           15      },
1746     { EL_BALLOON,               16      },
1747     { EL_SPRING,                17      },
1748
1749     { -1,                       -1      },
1750   };
1751
1752   static struct PropertyBitInfo pb_dont_collide_with[] =
1753   {
1754     { EL_SP_SNIKSNAK,           0       },
1755     { EL_SP_ELECTRON,           1       },
1756
1757     { -1,                       -1      },
1758   };
1759
1760   static struct
1761   {
1762     int bit_nr;
1763     struct PropertyBitInfo *pb_info;
1764   } pb_definition[] =
1765   {
1766     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
1767     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
1768
1769     { -1,                       NULL                    },
1770   };
1771
1772   struct PropertyBitInfo *pb_info = NULL;
1773   int i;
1774
1775   for (i = 0; pb_definition[i].bit_nr != -1; i++)
1776     if (pb_definition[i].bit_nr == property_bit_nr)
1777       pb_info = pb_definition[i].pb_info;
1778
1779   if (pb_info == NULL)
1780     return -1;
1781
1782   for (i = 0; pb_info[i].element != -1; i++)
1783     if (pb_info[i].element == element)
1784       return pb_info[i].bit_nr;
1785
1786   return -1;
1787 }
1788
1789 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1790                          boolean property_value)
1791 {
1792   int bit_nr = get_special_property_bit(element, property_bit_nr);
1793
1794   if (bit_nr > -1)
1795   {
1796     if (property_value)
1797       *bitfield |=  (1 << bit_nr);
1798     else
1799       *bitfield &= ~(1 << bit_nr);
1800   }
1801 }
1802
1803 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1804 {
1805   int bit_nr = get_special_property_bit(element, property_bit_nr);
1806
1807   if (bit_nr > -1)
1808     return ((*bitfield & (1 << bit_nr)) != 0);
1809
1810   return FALSE;
1811 }
1812
1813 void InitElementPropertiesStatic()
1814 {
1815   static int ep_diggable[] =
1816   {
1817     EL_SAND,
1818     EL_SP_BASE,
1819     EL_SP_BUGGY_BASE,
1820     EL_SP_BUGGY_BASE_ACTIVATING,
1821     EL_TRAP,
1822     EL_INVISIBLE_SAND,
1823     EL_INVISIBLE_SAND_ACTIVE,
1824     EL_EMC_GRASS,
1825
1826     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1827     /* (if amoeba can grow into anything diggable, maybe keep these out) */
1828 #if 0
1829     EL_LANDMINE,
1830     EL_TRAP_ACTIVE,
1831     EL_SP_BUGGY_BASE_ACTIVE,
1832     EL_EMC_PLANT,
1833 #endif
1834     -1
1835   };
1836
1837   static int ep_collectible_only[] =
1838   {
1839     EL_BD_DIAMOND,
1840     EL_EMERALD,
1841     EL_DIAMOND,
1842     EL_EMERALD_YELLOW,
1843     EL_EMERALD_RED,
1844     EL_EMERALD_PURPLE,
1845     EL_KEY_1,
1846     EL_KEY_2,
1847     EL_KEY_3,
1848     EL_KEY_4,
1849     EL_EM_KEY_1,
1850     EL_EM_KEY_2,
1851     EL_EM_KEY_3,
1852     EL_EM_KEY_4,
1853     EL_EMC_KEY_5,
1854     EL_EMC_KEY_6,
1855     EL_EMC_KEY_7,
1856     EL_EMC_KEY_8,
1857     EL_DYNAMITE,
1858     EL_DYNABOMB_INCREASE_NUMBER,
1859     EL_DYNABOMB_INCREASE_SIZE,
1860     EL_DYNABOMB_INCREASE_POWER,
1861     EL_SP_INFOTRON,
1862     EL_SP_DISK_RED,
1863     EL_PEARL,
1864     EL_CRYSTAL,
1865     EL_KEY_WHITE,
1866     EL_SHIELD_NORMAL,
1867     EL_SHIELD_DEADLY,
1868     EL_EXTRA_TIME,
1869     EL_ENVELOPE_1,
1870     EL_ENVELOPE_2,
1871     EL_ENVELOPE_3,
1872     EL_ENVELOPE_4,
1873     EL_SPEED_PILL,
1874     EL_EMC_LENSES,
1875     EL_EMC_MAGNIFIER,
1876     -1
1877   };
1878
1879   static int ep_dont_run_into[] =
1880   {
1881     /* same elements as in 'ep_dont_touch' */
1882     EL_BUG,
1883     EL_SPACESHIP,
1884     EL_BD_BUTTERFLY,
1885     EL_BD_FIREFLY,
1886
1887     /* same elements as in 'ep_dont_collide_with' */
1888     EL_YAMYAM,
1889     EL_DARK_YAMYAM,
1890     EL_ROBOT,
1891     EL_PACMAN,
1892     EL_SP_SNIKSNAK,
1893     EL_SP_ELECTRON,
1894
1895     /* new elements */
1896     EL_AMOEBA_DROP,
1897     EL_ACID,
1898
1899     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1900 #if 1
1901     EL_LANDMINE,
1902     EL_TRAP_ACTIVE,
1903     EL_SP_BUGGY_BASE_ACTIVE,
1904     EL_EMC_PLANT,
1905 #endif
1906     -1
1907   };
1908
1909   static int ep_dont_collide_with[] =
1910   {
1911     /* same elements as in 'ep_dont_touch' */
1912     EL_BUG,
1913     EL_SPACESHIP,
1914     EL_BD_BUTTERFLY,
1915     EL_BD_FIREFLY,
1916
1917     /* new elements */
1918     EL_YAMYAM,
1919     EL_DARK_YAMYAM,
1920     EL_ROBOT,
1921     EL_PACMAN,
1922     EL_SP_SNIKSNAK,
1923     EL_SP_ELECTRON,
1924     -1
1925   };
1926
1927   static int ep_dont_touch[] =
1928   {
1929     EL_BUG,
1930     EL_SPACESHIP,
1931     EL_BD_BUTTERFLY,
1932     EL_BD_FIREFLY,
1933     -1
1934   };
1935
1936   static int ep_indestructible[] =
1937   {
1938     EL_STEELWALL,
1939     EL_ACID,
1940     EL_ACID_POOL_TOPLEFT,
1941     EL_ACID_POOL_TOPRIGHT,
1942     EL_ACID_POOL_BOTTOMLEFT,
1943     EL_ACID_POOL_BOTTOM,
1944     EL_ACID_POOL_BOTTOMRIGHT,
1945     EL_SP_HARDWARE_GRAY,
1946     EL_SP_HARDWARE_GREEN,
1947     EL_SP_HARDWARE_BLUE,
1948     EL_SP_HARDWARE_RED,
1949     EL_SP_HARDWARE_YELLOW,
1950     EL_SP_HARDWARE_BASE_1,
1951     EL_SP_HARDWARE_BASE_2,
1952     EL_SP_HARDWARE_BASE_3,
1953     EL_SP_HARDWARE_BASE_4,
1954     EL_SP_HARDWARE_BASE_5,
1955     EL_SP_HARDWARE_BASE_6,
1956     EL_INVISIBLE_STEELWALL,
1957     EL_INVISIBLE_STEELWALL_ACTIVE,
1958     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1959     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1960     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1961     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1962     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1963     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1964     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1965     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
1966     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
1967     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
1968     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
1969     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
1970     EL_LIGHT_SWITCH,
1971     EL_LIGHT_SWITCH_ACTIVE,
1972     EL_SIGN_EXCLAMATION,
1973     EL_SIGN_RADIOACTIVITY,
1974     EL_SIGN_STOP,
1975     EL_SIGN_WHEELCHAIR,
1976     EL_SIGN_PARKING,
1977     EL_SIGN_ONEWAY,
1978     EL_SIGN_HEART,
1979     EL_SIGN_TRIANGLE,
1980     EL_SIGN_ROUND,
1981     EL_SIGN_EXIT,
1982     EL_SIGN_YINYANG,
1983     EL_SIGN_OTHER,
1984     EL_STEELWALL_SLIPPERY,
1985     EL_EMC_STEELWALL_1,
1986     EL_EMC_STEELWALL_2,
1987     EL_EMC_STEELWALL_3,
1988     EL_EMC_STEELWALL_4,
1989     EL_CRYSTAL,
1990     EL_GATE_1,
1991     EL_GATE_2,
1992     EL_GATE_3,
1993     EL_GATE_4,
1994     EL_GATE_1_GRAY,
1995     EL_GATE_2_GRAY,
1996     EL_GATE_3_GRAY,
1997     EL_GATE_4_GRAY,
1998     EL_EM_GATE_1,
1999     EL_EM_GATE_2,
2000     EL_EM_GATE_3,
2001     EL_EM_GATE_4,
2002     EL_EM_GATE_1_GRAY,
2003     EL_EM_GATE_2_GRAY,
2004     EL_EM_GATE_3_GRAY,
2005     EL_EM_GATE_4_GRAY,
2006     EL_EMC_GATE_5,
2007     EL_EMC_GATE_6,
2008     EL_EMC_GATE_7,
2009     EL_EMC_GATE_8,
2010     EL_EMC_GATE_5_GRAY,
2011     EL_EMC_GATE_6_GRAY,
2012     EL_EMC_GATE_7_GRAY,
2013     EL_EMC_GATE_8_GRAY,
2014     EL_SWITCHGATE_OPEN,
2015     EL_SWITCHGATE_OPENING,
2016     EL_SWITCHGATE_CLOSED,
2017     EL_SWITCHGATE_CLOSING,
2018 #if 0
2019     EL_SWITCHGATE_SWITCH_UP,
2020     EL_SWITCHGATE_SWITCH_DOWN,
2021 #endif
2022     EL_TIMEGATE_OPEN,
2023     EL_TIMEGATE_OPENING,
2024     EL_TIMEGATE_CLOSED,
2025     EL_TIMEGATE_CLOSING,
2026 #if 0
2027     EL_TIMEGATE_SWITCH,
2028     EL_TIMEGATE_SWITCH_ACTIVE,
2029 #endif
2030     EL_TUBE_ANY,
2031     EL_TUBE_VERTICAL,
2032     EL_TUBE_HORIZONTAL,
2033     EL_TUBE_VERTICAL_LEFT,
2034     EL_TUBE_VERTICAL_RIGHT,
2035     EL_TUBE_HORIZONTAL_UP,
2036     EL_TUBE_HORIZONTAL_DOWN,
2037     EL_TUBE_LEFT_UP,
2038     EL_TUBE_LEFT_DOWN,
2039     EL_TUBE_RIGHT_UP,
2040     EL_TUBE_RIGHT_DOWN,
2041     -1
2042   };
2043
2044   static int ep_slippery[] =
2045   {
2046     EL_WALL_SLIPPERY,
2047     EL_BD_WALL,
2048     EL_ROCK,
2049     EL_BD_ROCK,
2050     EL_EMERALD,
2051     EL_BD_DIAMOND,
2052     EL_EMERALD_YELLOW,
2053     EL_EMERALD_RED,
2054     EL_EMERALD_PURPLE,
2055     EL_DIAMOND,
2056     EL_BOMB,
2057     EL_NUT,
2058     EL_ROBOT_WHEEL_ACTIVE,
2059     EL_ROBOT_WHEEL,
2060     EL_TIME_ORB_FULL,
2061     EL_TIME_ORB_EMPTY,
2062     EL_LAMP_ACTIVE,
2063     EL_LAMP,
2064     EL_ACID_POOL_TOPLEFT,
2065     EL_ACID_POOL_TOPRIGHT,
2066     EL_SATELLITE,
2067     EL_SP_ZONK,
2068     EL_SP_INFOTRON,
2069     EL_SP_CHIP_SINGLE,
2070     EL_SP_CHIP_LEFT,
2071     EL_SP_CHIP_RIGHT,
2072     EL_SP_CHIP_TOP,
2073     EL_SP_CHIP_BOTTOM,
2074     EL_SPEED_PILL,
2075     EL_STEELWALL_SLIPPERY,
2076     EL_PEARL,
2077     EL_CRYSTAL,
2078     EL_EMC_WALL_SLIPPERY_1,
2079     EL_EMC_WALL_SLIPPERY_2,
2080     EL_EMC_WALL_SLIPPERY_3,
2081     EL_EMC_WALL_SLIPPERY_4,
2082     -1
2083   };
2084
2085   static int ep_can_change[] =
2086   {
2087     -1
2088   };
2089
2090   static int ep_can_move[] =
2091   {
2092     /* same elements as in 'pb_can_move_into_acid' */
2093     EL_BUG,
2094     EL_SPACESHIP,
2095     EL_BD_BUTTERFLY,
2096     EL_BD_FIREFLY,
2097     EL_YAMYAM,
2098     EL_DARK_YAMYAM,
2099     EL_ROBOT,
2100     EL_PACMAN,
2101     EL_MOLE,
2102     EL_PENGUIN,
2103     EL_PIG,
2104     EL_DRAGON,
2105     EL_SATELLITE,
2106     EL_SP_SNIKSNAK,
2107     EL_SP_ELECTRON,
2108     EL_BALLOON,
2109     EL_SPRING,
2110     EL_EMC_ANDROID,
2111     -1
2112   };
2113
2114   static int ep_can_fall[] =
2115   {
2116     EL_ROCK,
2117     EL_BD_ROCK,
2118     EL_EMERALD,
2119     EL_BD_DIAMOND,
2120     EL_EMERALD_YELLOW,
2121     EL_EMERALD_RED,
2122     EL_EMERALD_PURPLE,
2123     EL_DIAMOND,
2124     EL_BOMB,
2125     EL_NUT,
2126     EL_AMOEBA_DROP,
2127     EL_QUICKSAND_FULL,
2128     EL_MAGIC_WALL_FULL,
2129     EL_BD_MAGIC_WALL_FULL,
2130     EL_TIME_ORB_FULL,
2131     EL_TIME_ORB_EMPTY,
2132     EL_SP_ZONK,
2133     EL_SP_INFOTRON,
2134     EL_SP_DISK_ORANGE,
2135     EL_PEARL,
2136     EL_CRYSTAL,
2137     EL_SPRING,
2138     EL_DX_SUPABOMB,
2139     -1
2140   };
2141
2142   static int ep_can_smash_player[] =
2143   {
2144     EL_ROCK,
2145     EL_BD_ROCK,
2146     EL_EMERALD,
2147     EL_BD_DIAMOND,
2148     EL_EMERALD_YELLOW,
2149     EL_EMERALD_RED,
2150     EL_EMERALD_PURPLE,
2151     EL_DIAMOND,
2152     EL_BOMB,
2153     EL_NUT,
2154     EL_AMOEBA_DROP,
2155     EL_TIME_ORB_FULL,
2156     EL_TIME_ORB_EMPTY,
2157     EL_SP_ZONK,
2158     EL_SP_INFOTRON,
2159     EL_SP_DISK_ORANGE,
2160     EL_PEARL,
2161     EL_CRYSTAL,
2162     EL_SPRING,
2163     EL_DX_SUPABOMB,
2164     -1
2165   };
2166
2167   static int ep_can_smash_enemies[] =
2168   {
2169     EL_ROCK,
2170     EL_BD_ROCK,
2171     EL_SP_ZONK,
2172     -1
2173   };
2174
2175   static int ep_can_smash_everything[] =
2176   {
2177     EL_ROCK,
2178     EL_BD_ROCK,
2179     EL_SP_ZONK,
2180     -1
2181   };
2182
2183   static int ep_explodes_by_fire[] =
2184   {
2185     /* same elements as in 'ep_explodes_impact' */
2186     EL_BOMB,
2187     EL_SP_DISK_ORANGE,
2188     EL_DX_SUPABOMB,
2189
2190     /* same elements as in 'ep_explodes_smashed' */
2191     EL_SATELLITE,
2192     EL_PIG,
2193     EL_DRAGON,
2194     EL_MOLE,
2195
2196     /* new elements */
2197     EL_DYNAMITE_ACTIVE,
2198     EL_DYNAMITE,
2199     EL_DYNABOMB_PLAYER_1_ACTIVE,
2200     EL_DYNABOMB_PLAYER_2_ACTIVE,
2201     EL_DYNABOMB_PLAYER_3_ACTIVE,
2202     EL_DYNABOMB_PLAYER_4_ACTIVE,
2203     EL_DYNABOMB_INCREASE_NUMBER,
2204     EL_DYNABOMB_INCREASE_SIZE,
2205     EL_DYNABOMB_INCREASE_POWER,
2206     EL_SP_DISK_RED_ACTIVE,
2207     EL_BUG,
2208     EL_PENGUIN,
2209     EL_SP_DISK_RED,
2210     EL_SP_DISK_YELLOW,
2211     EL_SP_SNIKSNAK,
2212     EL_SP_ELECTRON,
2213 #if 0
2214     EL_BLACK_ORB,
2215 #endif
2216     -1
2217   };
2218
2219   static int ep_explodes_smashed[] =
2220   {
2221     /* same elements as in 'ep_explodes_impact' */
2222     EL_BOMB,
2223     EL_SP_DISK_ORANGE,
2224     EL_DX_SUPABOMB,
2225
2226     /* new elements */
2227     EL_SATELLITE,
2228     EL_PIG,
2229     EL_DRAGON,
2230     EL_MOLE,
2231     -1
2232   };
2233
2234   static int ep_explodes_impact[] =
2235   {
2236     EL_BOMB,
2237     EL_SP_DISK_ORANGE,
2238     EL_DX_SUPABOMB,
2239     -1
2240   };
2241
2242   static int ep_walkable_over[] =
2243   {
2244     EL_EMPTY_SPACE,
2245     EL_SP_EMPTY_SPACE,
2246     EL_SOKOBAN_FIELD_EMPTY,
2247     EL_EXIT_OPEN,
2248     EL_SP_EXIT_OPEN,
2249     EL_SP_EXIT_OPENING,
2250     EL_GATE_1,
2251     EL_GATE_2,
2252     EL_GATE_3,
2253     EL_GATE_4,
2254     EL_GATE_1_GRAY,
2255     EL_GATE_2_GRAY,
2256     EL_GATE_3_GRAY,
2257     EL_GATE_4_GRAY,
2258     EL_PENGUIN,
2259     EL_PIG,
2260     EL_DRAGON,
2261     -1
2262   };
2263
2264   static int ep_walkable_inside[] =
2265   {
2266     EL_TUBE_ANY,
2267     EL_TUBE_VERTICAL,
2268     EL_TUBE_HORIZONTAL,
2269     EL_TUBE_VERTICAL_LEFT,
2270     EL_TUBE_VERTICAL_RIGHT,
2271     EL_TUBE_HORIZONTAL_UP,
2272     EL_TUBE_HORIZONTAL_DOWN,
2273     EL_TUBE_LEFT_UP,
2274     EL_TUBE_LEFT_DOWN,
2275     EL_TUBE_RIGHT_UP,
2276     EL_TUBE_RIGHT_DOWN,
2277     -1
2278   };
2279
2280   static int ep_walkable_under[] =
2281   {
2282     -1
2283   };
2284
2285   static int ep_passable_over[] =
2286   {
2287     EL_EM_GATE_1,
2288     EL_EM_GATE_2,
2289     EL_EM_GATE_3,
2290     EL_EM_GATE_4,
2291     EL_EM_GATE_1_GRAY,
2292     EL_EM_GATE_2_GRAY,
2293     EL_EM_GATE_3_GRAY,
2294     EL_EM_GATE_4_GRAY,
2295     EL_EMC_GATE_5,
2296     EL_EMC_GATE_6,
2297     EL_EMC_GATE_7,
2298     EL_EMC_GATE_8,
2299     EL_EMC_GATE_5_GRAY,
2300     EL_EMC_GATE_6_GRAY,
2301     EL_EMC_GATE_7_GRAY,
2302     EL_EMC_GATE_8_GRAY,
2303     EL_SWITCHGATE_OPEN,
2304     EL_TIMEGATE_OPEN,
2305     -1
2306   };
2307
2308   static int ep_passable_inside[] =
2309   {
2310     EL_SP_PORT_LEFT,
2311     EL_SP_PORT_RIGHT,
2312     EL_SP_PORT_UP,
2313     EL_SP_PORT_DOWN,
2314     EL_SP_PORT_HORIZONTAL,
2315     EL_SP_PORT_VERTICAL,
2316     EL_SP_PORT_ANY,
2317     EL_SP_GRAVITY_PORT_LEFT,
2318     EL_SP_GRAVITY_PORT_RIGHT,
2319     EL_SP_GRAVITY_PORT_UP,
2320     EL_SP_GRAVITY_PORT_DOWN,
2321     EL_SP_GRAVITY_ON_PORT_LEFT,
2322     EL_SP_GRAVITY_ON_PORT_RIGHT,
2323     EL_SP_GRAVITY_ON_PORT_UP,
2324     EL_SP_GRAVITY_ON_PORT_DOWN,
2325     EL_SP_GRAVITY_OFF_PORT_LEFT,
2326     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2327     EL_SP_GRAVITY_OFF_PORT_UP,
2328     EL_SP_GRAVITY_OFF_PORT_DOWN,
2329     -1
2330   };
2331
2332   static int ep_passable_under[] =
2333   {
2334     -1
2335   };
2336
2337   static int ep_droppable[] =
2338   {
2339     -1
2340   };
2341
2342   static int ep_explodes_1x1_old[] =
2343   {
2344     -1
2345   };
2346
2347   static int ep_pushable[] =
2348   {
2349     EL_ROCK,
2350     EL_BOMB,
2351     EL_DX_SUPABOMB,
2352     EL_NUT,
2353     EL_TIME_ORB_EMPTY,
2354     EL_SP_ZONK,
2355     EL_SP_DISK_ORANGE,
2356     EL_SPRING,
2357     EL_BD_ROCK,
2358     EL_SOKOBAN_OBJECT,
2359     EL_SOKOBAN_FIELD_FULL,
2360     EL_SATELLITE,
2361     EL_SP_DISK_YELLOW,
2362     EL_BALLOON,
2363     EL_EMC_ANDROID,
2364     -1
2365   };
2366
2367   static int ep_explodes_cross_old[] =
2368   {
2369     -1
2370   };
2371
2372   static int ep_protected[] =
2373   {
2374     /* same elements as in 'ep_walkable_inside' */
2375     EL_TUBE_ANY,
2376     EL_TUBE_VERTICAL,
2377     EL_TUBE_HORIZONTAL,
2378     EL_TUBE_VERTICAL_LEFT,
2379     EL_TUBE_VERTICAL_RIGHT,
2380     EL_TUBE_HORIZONTAL_UP,
2381     EL_TUBE_HORIZONTAL_DOWN,
2382     EL_TUBE_LEFT_UP,
2383     EL_TUBE_LEFT_DOWN,
2384     EL_TUBE_RIGHT_UP,
2385     EL_TUBE_RIGHT_DOWN,
2386
2387     /* same elements as in 'ep_passable_over' */
2388     EL_EM_GATE_1,
2389     EL_EM_GATE_2,
2390     EL_EM_GATE_3,
2391     EL_EM_GATE_4,
2392     EL_EM_GATE_1_GRAY,
2393     EL_EM_GATE_2_GRAY,
2394     EL_EM_GATE_3_GRAY,
2395     EL_EM_GATE_4_GRAY,
2396     EL_EMC_GATE_5,
2397     EL_EMC_GATE_6,
2398     EL_EMC_GATE_7,
2399     EL_EMC_GATE_8,
2400     EL_EMC_GATE_5_GRAY,
2401     EL_EMC_GATE_6_GRAY,
2402     EL_EMC_GATE_7_GRAY,
2403     EL_EMC_GATE_8_GRAY,
2404     EL_SWITCHGATE_OPEN,
2405     EL_TIMEGATE_OPEN,
2406
2407     /* same elements as in 'ep_passable_inside' */
2408     EL_SP_PORT_LEFT,
2409     EL_SP_PORT_RIGHT,
2410     EL_SP_PORT_UP,
2411     EL_SP_PORT_DOWN,
2412     EL_SP_PORT_HORIZONTAL,
2413     EL_SP_PORT_VERTICAL,
2414     EL_SP_PORT_ANY,
2415     EL_SP_GRAVITY_PORT_LEFT,
2416     EL_SP_GRAVITY_PORT_RIGHT,
2417     EL_SP_GRAVITY_PORT_UP,
2418     EL_SP_GRAVITY_PORT_DOWN,
2419     EL_SP_GRAVITY_ON_PORT_LEFT,
2420     EL_SP_GRAVITY_ON_PORT_RIGHT,
2421     EL_SP_GRAVITY_ON_PORT_UP,
2422     EL_SP_GRAVITY_ON_PORT_DOWN,
2423     EL_SP_GRAVITY_OFF_PORT_LEFT,
2424     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2425     EL_SP_GRAVITY_OFF_PORT_UP,
2426     EL_SP_GRAVITY_OFF_PORT_DOWN,
2427     -1
2428   };
2429
2430   static int ep_throwable[] =
2431   {
2432     -1
2433   };
2434
2435   static int ep_can_explode[] =
2436   {
2437     /* same elements as in 'ep_explodes_impact' */
2438     EL_BOMB,
2439     EL_SP_DISK_ORANGE,
2440     EL_DX_SUPABOMB,
2441
2442     /* same elements as in 'ep_explodes_smashed' */
2443     EL_SATELLITE,
2444     EL_PIG,
2445     EL_DRAGON,
2446     EL_MOLE,
2447
2448     /* elements that can explode by explosion or by dragonfire */
2449     EL_DYNAMITE_ACTIVE,
2450     EL_DYNAMITE,
2451     EL_DYNABOMB_PLAYER_1_ACTIVE,
2452     EL_DYNABOMB_PLAYER_2_ACTIVE,
2453     EL_DYNABOMB_PLAYER_3_ACTIVE,
2454     EL_DYNABOMB_PLAYER_4_ACTIVE,
2455     EL_DYNABOMB_INCREASE_NUMBER,
2456     EL_DYNABOMB_INCREASE_SIZE,
2457     EL_DYNABOMB_INCREASE_POWER,
2458     EL_SP_DISK_RED_ACTIVE,
2459     EL_BUG,
2460     EL_PENGUIN,
2461     EL_SP_DISK_RED,
2462     EL_SP_DISK_YELLOW,
2463     EL_SP_SNIKSNAK,
2464     EL_SP_ELECTRON,
2465
2466     /* elements that can explode only by explosion */
2467     EL_BLACK_ORB,
2468     -1
2469   };
2470
2471   static int ep_gravity_reachable[] =
2472   {
2473     EL_SAND,
2474     EL_SP_BASE,
2475     EL_TRAP,
2476     EL_INVISIBLE_SAND,
2477     EL_INVISIBLE_SAND_ACTIVE,
2478     EL_SP_PORT_LEFT,
2479     EL_SP_PORT_RIGHT,
2480     EL_SP_PORT_UP,
2481     EL_SP_PORT_DOWN,
2482     EL_SP_PORT_HORIZONTAL,
2483     EL_SP_PORT_VERTICAL,
2484     EL_SP_PORT_ANY,
2485     EL_SP_GRAVITY_PORT_LEFT,
2486     EL_SP_GRAVITY_PORT_RIGHT,
2487     EL_SP_GRAVITY_PORT_UP,
2488     EL_SP_GRAVITY_PORT_DOWN,
2489     EL_SP_GRAVITY_ON_PORT_LEFT,
2490     EL_SP_GRAVITY_ON_PORT_RIGHT,
2491     EL_SP_GRAVITY_ON_PORT_UP,
2492     EL_SP_GRAVITY_ON_PORT_DOWN,
2493     EL_SP_GRAVITY_OFF_PORT_LEFT,
2494     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2495     EL_SP_GRAVITY_OFF_PORT_UP,
2496     EL_SP_GRAVITY_OFF_PORT_DOWN,
2497     EL_EMC_GRASS,
2498     -1
2499   };
2500
2501   static int ep_player[] =
2502   {
2503     EL_PLAYER_1,
2504     EL_PLAYER_2,
2505     EL_PLAYER_3,
2506     EL_PLAYER_4,
2507     EL_SP_MURPHY,
2508     EL_SOKOBAN_FIELD_PLAYER,
2509     EL_TRIGGER_PLAYER,
2510     -1
2511   };
2512
2513   static int ep_can_pass_magic_wall[] =
2514   {
2515     EL_ROCK,
2516     EL_BD_ROCK,
2517     EL_EMERALD,
2518     EL_BD_DIAMOND,
2519     EL_EMERALD_YELLOW,
2520     EL_EMERALD_RED,
2521     EL_EMERALD_PURPLE,
2522     EL_DIAMOND,
2523     -1
2524   };
2525
2526   static int ep_switchable[] =
2527   {
2528     EL_ROBOT_WHEEL,
2529     EL_SP_TERMINAL,
2530     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2531     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2532     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2533     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2534     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2535     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2536     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2537     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2538     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2539     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2540     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2541     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2542     EL_SWITCHGATE_SWITCH_UP,
2543     EL_SWITCHGATE_SWITCH_DOWN,
2544     EL_LIGHT_SWITCH,
2545     EL_LIGHT_SWITCH_ACTIVE,
2546     EL_TIMEGATE_SWITCH,
2547     EL_BALLOON_SWITCH_LEFT,
2548     EL_BALLOON_SWITCH_RIGHT,
2549     EL_BALLOON_SWITCH_UP,
2550     EL_BALLOON_SWITCH_DOWN,
2551     EL_BALLOON_SWITCH_ANY,
2552     EL_LAMP,
2553     EL_TIME_ORB_FULL,
2554     EL_EMC_MAGIC_BALL_SWITCH,
2555     -1
2556   };
2557
2558   static int ep_bd_element[] =
2559   {
2560     EL_EMPTY,
2561     EL_SAND,
2562     EL_WALL_SLIPPERY,
2563     EL_BD_WALL,
2564     EL_ROCK,
2565     EL_BD_ROCK,
2566     EL_BD_DIAMOND,
2567     EL_BD_MAGIC_WALL,
2568     EL_EXIT_CLOSED,
2569     EL_EXIT_OPEN,
2570     EL_STEELWALL,
2571     EL_PLAYER_1,
2572     EL_PLAYER_2,
2573     EL_PLAYER_3,
2574     EL_PLAYER_4,
2575     EL_BD_FIREFLY,
2576     EL_BD_FIREFLY_1,
2577     EL_BD_FIREFLY_2,
2578     EL_BD_FIREFLY_3,
2579     EL_BD_FIREFLY_4,
2580     EL_BD_BUTTERFLY,
2581     EL_BD_BUTTERFLY_1,
2582     EL_BD_BUTTERFLY_2,
2583     EL_BD_BUTTERFLY_3,
2584     EL_BD_BUTTERFLY_4,
2585     EL_BD_AMOEBA,
2586     EL_CHAR_QUESTION,
2587     EL_UNKNOWN,
2588     -1
2589   };
2590
2591   static int ep_sp_element[] =
2592   {
2593     /* should always be valid */
2594     EL_EMPTY,
2595
2596     /* standard classic Supaplex elements */
2597     EL_SP_EMPTY,
2598     EL_SP_ZONK,
2599     EL_SP_BASE,
2600     EL_SP_MURPHY,
2601     EL_SP_INFOTRON,
2602     EL_SP_CHIP_SINGLE,
2603     EL_SP_HARDWARE_GRAY,
2604     EL_SP_EXIT_CLOSED,
2605     EL_SP_EXIT_OPEN,
2606     EL_SP_DISK_ORANGE,
2607     EL_SP_PORT_RIGHT,
2608     EL_SP_PORT_DOWN,
2609     EL_SP_PORT_LEFT,
2610     EL_SP_PORT_UP,
2611     EL_SP_GRAVITY_PORT_RIGHT,
2612     EL_SP_GRAVITY_PORT_DOWN,
2613     EL_SP_GRAVITY_PORT_LEFT,
2614     EL_SP_GRAVITY_PORT_UP,
2615     EL_SP_SNIKSNAK,
2616     EL_SP_DISK_YELLOW,
2617     EL_SP_TERMINAL,
2618     EL_SP_DISK_RED,
2619     EL_SP_PORT_VERTICAL,
2620     EL_SP_PORT_HORIZONTAL,
2621     EL_SP_PORT_ANY,
2622     EL_SP_ELECTRON,
2623     EL_SP_BUGGY_BASE,
2624     EL_SP_CHIP_LEFT,
2625     EL_SP_CHIP_RIGHT,
2626     EL_SP_HARDWARE_BASE_1,
2627     EL_SP_HARDWARE_GREEN,
2628     EL_SP_HARDWARE_BLUE,
2629     EL_SP_HARDWARE_RED,
2630     EL_SP_HARDWARE_YELLOW,
2631     EL_SP_HARDWARE_BASE_2,
2632     EL_SP_HARDWARE_BASE_3,
2633     EL_SP_HARDWARE_BASE_4,
2634     EL_SP_HARDWARE_BASE_5,
2635     EL_SP_HARDWARE_BASE_6,
2636     EL_SP_CHIP_TOP,
2637     EL_SP_CHIP_BOTTOM,
2638
2639     /* additional elements that appeared in newer Supaplex levels */
2640     EL_INVISIBLE_WALL,
2641
2642     /* additional gravity port elements (not switching, but setting gravity) */
2643     EL_SP_GRAVITY_ON_PORT_LEFT,
2644     EL_SP_GRAVITY_ON_PORT_RIGHT,
2645     EL_SP_GRAVITY_ON_PORT_UP,
2646     EL_SP_GRAVITY_ON_PORT_DOWN,
2647     EL_SP_GRAVITY_OFF_PORT_LEFT,
2648     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2649     EL_SP_GRAVITY_OFF_PORT_UP,
2650     EL_SP_GRAVITY_OFF_PORT_DOWN,
2651
2652     /* more than one Murphy in a level results in an inactive clone */
2653     EL_SP_MURPHY_CLONE,
2654
2655     /* runtime Supaplex elements */
2656     EL_SP_DISK_RED_ACTIVE,
2657     EL_SP_TERMINAL_ACTIVE,
2658     EL_SP_BUGGY_BASE_ACTIVATING,
2659     EL_SP_BUGGY_BASE_ACTIVE,
2660     EL_SP_EXIT_OPENING,
2661     EL_SP_EXIT_CLOSING,
2662     -1
2663   };
2664
2665   static int ep_sb_element[] =
2666   {
2667     EL_EMPTY,
2668     EL_STEELWALL,
2669     EL_SOKOBAN_OBJECT,
2670     EL_SOKOBAN_FIELD_EMPTY,
2671     EL_SOKOBAN_FIELD_FULL,
2672     EL_SOKOBAN_FIELD_PLAYER,
2673     EL_PLAYER_1,
2674     EL_PLAYER_2,
2675     EL_PLAYER_3,
2676     EL_PLAYER_4,
2677     EL_INVISIBLE_STEELWALL,
2678     -1
2679   };
2680
2681   static int ep_gem[] =
2682   {
2683     EL_BD_DIAMOND,
2684     EL_EMERALD,
2685     EL_EMERALD_YELLOW,
2686     EL_EMERALD_RED,
2687     EL_EMERALD_PURPLE,
2688     EL_DIAMOND,
2689     -1
2690   };
2691
2692   static int ep_food_dark_yamyam[] =
2693   {
2694     EL_SAND,
2695     EL_BUG,
2696     EL_SPACESHIP,
2697     EL_BD_BUTTERFLY,
2698     EL_BD_FIREFLY,
2699     EL_YAMYAM,
2700     EL_ROBOT,
2701     EL_PACMAN,
2702     EL_AMOEBA_DROP,
2703     EL_AMOEBA_DEAD,
2704     EL_AMOEBA_WET,
2705     EL_AMOEBA_DRY,
2706     EL_AMOEBA_FULL,
2707     EL_BD_AMOEBA,
2708     EL_EMERALD,
2709     EL_BD_DIAMOND,
2710     EL_EMERALD_YELLOW,
2711     EL_EMERALD_RED,
2712     EL_EMERALD_PURPLE,
2713     EL_DIAMOND,
2714     EL_PEARL,
2715     EL_CRYSTAL,
2716     -1
2717   };
2718
2719   static int ep_food_penguin[] =
2720   {
2721     EL_EMERALD,
2722     EL_BD_DIAMOND,
2723     EL_EMERALD_YELLOW,
2724     EL_EMERALD_RED,
2725     EL_EMERALD_PURPLE,
2726     EL_DIAMOND,
2727     EL_PEARL,
2728     EL_CRYSTAL,
2729     -1
2730   };
2731
2732   static int ep_food_pig[] =
2733   {
2734     EL_EMERALD,
2735     EL_BD_DIAMOND,
2736     EL_EMERALD_YELLOW,
2737     EL_EMERALD_RED,
2738     EL_EMERALD_PURPLE,
2739     EL_DIAMOND,
2740     -1
2741   };
2742
2743   static int ep_historic_wall[] =
2744   {
2745     EL_STEELWALL,
2746     EL_GATE_1,
2747     EL_GATE_2,
2748     EL_GATE_3,
2749     EL_GATE_4,
2750     EL_GATE_1_GRAY,
2751     EL_GATE_2_GRAY,
2752     EL_GATE_3_GRAY,
2753     EL_GATE_4_GRAY,
2754     EL_EM_GATE_1,
2755     EL_EM_GATE_2,
2756     EL_EM_GATE_3,
2757     EL_EM_GATE_4,
2758     EL_EM_GATE_1_GRAY,
2759     EL_EM_GATE_2_GRAY,
2760     EL_EM_GATE_3_GRAY,
2761     EL_EM_GATE_4_GRAY,
2762     EL_EXIT_CLOSED,
2763     EL_EXIT_OPENING,
2764     EL_EXIT_OPEN,
2765     EL_WALL,
2766     EL_WALL_SLIPPERY,
2767     EL_EXPANDABLE_WALL,
2768     EL_EXPANDABLE_WALL_HORIZONTAL,
2769     EL_EXPANDABLE_WALL_VERTICAL,
2770     EL_EXPANDABLE_WALL_ANY,
2771     EL_EXPANDABLE_WALL_GROWING,
2772     EL_BD_WALL,
2773     EL_SP_CHIP_SINGLE,
2774     EL_SP_CHIP_LEFT,
2775     EL_SP_CHIP_RIGHT,
2776     EL_SP_CHIP_TOP,
2777     EL_SP_CHIP_BOTTOM,
2778     EL_SP_HARDWARE_GRAY,
2779     EL_SP_HARDWARE_GREEN,
2780     EL_SP_HARDWARE_BLUE,
2781     EL_SP_HARDWARE_RED,
2782     EL_SP_HARDWARE_YELLOW,
2783     EL_SP_HARDWARE_BASE_1,
2784     EL_SP_HARDWARE_BASE_2,
2785     EL_SP_HARDWARE_BASE_3,
2786     EL_SP_HARDWARE_BASE_4,
2787     EL_SP_HARDWARE_BASE_5,
2788     EL_SP_HARDWARE_BASE_6,
2789     EL_SP_TERMINAL,
2790     EL_SP_TERMINAL_ACTIVE,
2791     EL_SP_EXIT_CLOSED,
2792     EL_SP_EXIT_OPEN,
2793     EL_INVISIBLE_STEELWALL,
2794     EL_INVISIBLE_STEELWALL_ACTIVE,
2795     EL_INVISIBLE_WALL,
2796     EL_INVISIBLE_WALL_ACTIVE,
2797     EL_STEELWALL_SLIPPERY,
2798     EL_EMC_STEELWALL_1,
2799     EL_EMC_STEELWALL_2,
2800     EL_EMC_STEELWALL_3,
2801     EL_EMC_STEELWALL_4,
2802     EL_EMC_WALL_1,
2803     EL_EMC_WALL_2,
2804     EL_EMC_WALL_3,
2805     EL_EMC_WALL_4,
2806     EL_EMC_WALL_5,
2807     EL_EMC_WALL_6,
2808     EL_EMC_WALL_7,
2809     EL_EMC_WALL_8,
2810     -1
2811   };
2812
2813   static int ep_historic_solid[] =
2814   {
2815     EL_WALL,
2816     EL_EXPANDABLE_WALL,
2817     EL_EXPANDABLE_WALL_HORIZONTAL,
2818     EL_EXPANDABLE_WALL_VERTICAL,
2819     EL_EXPANDABLE_WALL_ANY,
2820     EL_BD_WALL,
2821     EL_WALL_SLIPPERY,
2822     EL_EXIT_CLOSED,
2823     EL_EXIT_OPENING,
2824     EL_EXIT_OPEN,
2825     EL_AMOEBA_DEAD,
2826     EL_AMOEBA_WET,
2827     EL_AMOEBA_DRY,
2828     EL_AMOEBA_FULL,
2829     EL_BD_AMOEBA,
2830     EL_QUICKSAND_EMPTY,
2831     EL_QUICKSAND_FULL,
2832     EL_QUICKSAND_FILLING,
2833     EL_QUICKSAND_EMPTYING,
2834     EL_MAGIC_WALL,
2835     EL_MAGIC_WALL_ACTIVE,
2836     EL_MAGIC_WALL_EMPTYING,
2837     EL_MAGIC_WALL_FILLING,
2838     EL_MAGIC_WALL_FULL,
2839     EL_MAGIC_WALL_DEAD,
2840     EL_BD_MAGIC_WALL,
2841     EL_BD_MAGIC_WALL_ACTIVE,
2842     EL_BD_MAGIC_WALL_EMPTYING,
2843     EL_BD_MAGIC_WALL_FULL,
2844     EL_BD_MAGIC_WALL_FILLING,
2845     EL_BD_MAGIC_WALL_DEAD,
2846     EL_GAME_OF_LIFE,
2847     EL_BIOMAZE,
2848     EL_SP_CHIP_SINGLE,
2849     EL_SP_CHIP_LEFT,
2850     EL_SP_CHIP_RIGHT,
2851     EL_SP_CHIP_TOP,
2852     EL_SP_CHIP_BOTTOM,
2853     EL_SP_TERMINAL,
2854     EL_SP_TERMINAL_ACTIVE,
2855     EL_SP_EXIT_CLOSED,
2856     EL_SP_EXIT_OPEN,
2857     EL_INVISIBLE_WALL,
2858     EL_INVISIBLE_WALL_ACTIVE,
2859     EL_SWITCHGATE_SWITCH_UP,
2860     EL_SWITCHGATE_SWITCH_DOWN,
2861     EL_TIMEGATE_SWITCH,
2862     EL_TIMEGATE_SWITCH_ACTIVE,
2863     EL_EMC_WALL_1,
2864     EL_EMC_WALL_2,
2865     EL_EMC_WALL_3,
2866     EL_EMC_WALL_4,
2867     EL_EMC_WALL_5,
2868     EL_EMC_WALL_6,
2869     EL_EMC_WALL_7,
2870     EL_EMC_WALL_8,
2871     EL_WALL_PEARL,
2872     EL_WALL_CRYSTAL,
2873
2874     /* the following elements are a direct copy of "indestructible" elements,
2875        except "EL_ACID", which is "indestructible", but not "solid"! */
2876 #if 0
2877     EL_ACID,
2878 #endif
2879     EL_STEELWALL,
2880     EL_ACID_POOL_TOPLEFT,
2881     EL_ACID_POOL_TOPRIGHT,
2882     EL_ACID_POOL_BOTTOMLEFT,
2883     EL_ACID_POOL_BOTTOM,
2884     EL_ACID_POOL_BOTTOMRIGHT,
2885     EL_SP_HARDWARE_GRAY,
2886     EL_SP_HARDWARE_GREEN,
2887     EL_SP_HARDWARE_BLUE,
2888     EL_SP_HARDWARE_RED,
2889     EL_SP_HARDWARE_YELLOW,
2890     EL_SP_HARDWARE_BASE_1,
2891     EL_SP_HARDWARE_BASE_2,
2892     EL_SP_HARDWARE_BASE_3,
2893     EL_SP_HARDWARE_BASE_4,
2894     EL_SP_HARDWARE_BASE_5,
2895     EL_SP_HARDWARE_BASE_6,
2896     EL_INVISIBLE_STEELWALL,
2897     EL_INVISIBLE_STEELWALL_ACTIVE,
2898     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2899     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2900     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2901     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2902     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2903     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2904     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2905     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2906     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2907     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2908     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2909     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2910     EL_LIGHT_SWITCH,
2911     EL_LIGHT_SWITCH_ACTIVE,
2912     EL_SIGN_EXCLAMATION,
2913     EL_SIGN_RADIOACTIVITY,
2914     EL_SIGN_STOP,
2915     EL_SIGN_WHEELCHAIR,
2916     EL_SIGN_PARKING,
2917     EL_SIGN_ONEWAY,
2918     EL_SIGN_HEART,
2919     EL_SIGN_TRIANGLE,
2920     EL_SIGN_ROUND,
2921     EL_SIGN_EXIT,
2922     EL_SIGN_YINYANG,
2923     EL_SIGN_OTHER,
2924     EL_STEELWALL_SLIPPERY,
2925     EL_EMC_STEELWALL_1,
2926     EL_EMC_STEELWALL_2,
2927     EL_EMC_STEELWALL_3,
2928     EL_EMC_STEELWALL_4,
2929     EL_CRYSTAL,
2930     EL_GATE_1,
2931     EL_GATE_2,
2932     EL_GATE_3,
2933     EL_GATE_4,
2934     EL_GATE_1_GRAY,
2935     EL_GATE_2_GRAY,
2936     EL_GATE_3_GRAY,
2937     EL_GATE_4_GRAY,
2938     EL_EM_GATE_1,
2939     EL_EM_GATE_2,
2940     EL_EM_GATE_3,
2941     EL_EM_GATE_4,
2942     EL_EM_GATE_1_GRAY,
2943     EL_EM_GATE_2_GRAY,
2944     EL_EM_GATE_3_GRAY,
2945     EL_EM_GATE_4_GRAY,
2946     EL_SWITCHGATE_OPEN,
2947     EL_SWITCHGATE_OPENING,
2948     EL_SWITCHGATE_CLOSED,
2949     EL_SWITCHGATE_CLOSING,
2950     EL_TIMEGATE_OPEN,
2951     EL_TIMEGATE_OPENING,
2952     EL_TIMEGATE_CLOSED,
2953     EL_TIMEGATE_CLOSING,
2954     EL_TUBE_ANY,
2955     EL_TUBE_VERTICAL,
2956     EL_TUBE_HORIZONTAL,
2957     EL_TUBE_VERTICAL_LEFT,
2958     EL_TUBE_VERTICAL_RIGHT,
2959     EL_TUBE_HORIZONTAL_UP,
2960     EL_TUBE_HORIZONTAL_DOWN,
2961     EL_TUBE_LEFT_UP,
2962     EL_TUBE_LEFT_DOWN,
2963     EL_TUBE_RIGHT_UP,
2964     EL_TUBE_RIGHT_DOWN,
2965     -1
2966   };
2967
2968   static int ep_classic_enemy[] =
2969   {
2970     EL_BUG,
2971     EL_SPACESHIP,
2972     EL_BD_BUTTERFLY,
2973     EL_BD_FIREFLY,
2974
2975     EL_YAMYAM,
2976     EL_DARK_YAMYAM,
2977     EL_ROBOT,
2978     EL_PACMAN,
2979     EL_SP_SNIKSNAK,
2980     EL_SP_ELECTRON,
2981     -1
2982   };
2983
2984   static int ep_belt[] =
2985   {
2986     EL_CONVEYOR_BELT_1_LEFT,
2987     EL_CONVEYOR_BELT_1_MIDDLE,
2988     EL_CONVEYOR_BELT_1_RIGHT,
2989     EL_CONVEYOR_BELT_2_LEFT,
2990     EL_CONVEYOR_BELT_2_MIDDLE,
2991     EL_CONVEYOR_BELT_2_RIGHT,
2992     EL_CONVEYOR_BELT_3_LEFT,
2993     EL_CONVEYOR_BELT_3_MIDDLE,
2994     EL_CONVEYOR_BELT_3_RIGHT,
2995     EL_CONVEYOR_BELT_4_LEFT,
2996     EL_CONVEYOR_BELT_4_MIDDLE,
2997     EL_CONVEYOR_BELT_4_RIGHT,
2998     -1
2999   };
3000
3001   static int ep_belt_active[] =
3002   {
3003     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3004     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3005     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3006     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3007     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3008     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3009     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3010     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3011     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3012     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3013     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3014     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3015     -1
3016   };
3017
3018   static int ep_belt_switch[] =
3019   {
3020     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3021     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3022     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3023     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3024     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3025     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3026     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3027     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3028     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3029     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3030     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3031     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3032     -1
3033   };
3034
3035   static int ep_tube[] =
3036   {
3037     EL_TUBE_LEFT_UP,
3038     EL_TUBE_LEFT_DOWN,
3039     EL_TUBE_RIGHT_UP,
3040     EL_TUBE_RIGHT_DOWN,
3041     EL_TUBE_HORIZONTAL,
3042     EL_TUBE_HORIZONTAL_UP,
3043     EL_TUBE_HORIZONTAL_DOWN,
3044     EL_TUBE_VERTICAL,
3045     EL_TUBE_VERTICAL_LEFT,
3046     EL_TUBE_VERTICAL_RIGHT,
3047     EL_TUBE_ANY,
3048     -1
3049   };
3050
3051   static int ep_keygate[] =
3052   {
3053     EL_GATE_1,
3054     EL_GATE_2,
3055     EL_GATE_3,
3056     EL_GATE_4,
3057     EL_GATE_1_GRAY,
3058     EL_GATE_2_GRAY,
3059     EL_GATE_3_GRAY,
3060     EL_GATE_4_GRAY,
3061     EL_EM_GATE_1,
3062     EL_EM_GATE_2,
3063     EL_EM_GATE_3,
3064     EL_EM_GATE_4,
3065     EL_EM_GATE_1_GRAY,
3066     EL_EM_GATE_2_GRAY,
3067     EL_EM_GATE_3_GRAY,
3068     EL_EM_GATE_4_GRAY,
3069     EL_EMC_GATE_5,
3070     EL_EMC_GATE_6,
3071     EL_EMC_GATE_7,
3072     EL_EMC_GATE_8,
3073     EL_EMC_GATE_5_GRAY,
3074     EL_EMC_GATE_6_GRAY,
3075     EL_EMC_GATE_7_GRAY,
3076     EL_EMC_GATE_8_GRAY,
3077     -1
3078   };
3079
3080   static int ep_amoeboid[] =
3081   {
3082     EL_AMOEBA_DEAD,
3083     EL_AMOEBA_WET,
3084     EL_AMOEBA_DRY,
3085     EL_AMOEBA_FULL,
3086     EL_BD_AMOEBA,
3087     -1
3088   };
3089
3090   static int ep_amoebalive[] =
3091   {
3092     EL_AMOEBA_WET,
3093     EL_AMOEBA_DRY,
3094     EL_AMOEBA_FULL,
3095     EL_BD_AMOEBA,
3096     -1
3097   };
3098
3099   static int ep_has_content[] =
3100   {
3101     EL_YAMYAM,
3102     EL_AMOEBA_WET,
3103     EL_AMOEBA_DRY,
3104     EL_AMOEBA_FULL,
3105     EL_BD_AMOEBA,
3106     -1
3107   };
3108
3109   static int ep_can_turn_each_move[] =
3110   {
3111     /* !!! do something with this one !!! */
3112     -1
3113   };
3114
3115   static int ep_can_grow[] =
3116   {
3117     EL_BD_AMOEBA,
3118     EL_AMOEBA_DROP,
3119     EL_AMOEBA_WET,
3120     EL_AMOEBA_DRY,
3121     EL_AMOEBA_FULL,
3122     EL_GAME_OF_LIFE,
3123     EL_BIOMAZE,
3124     -1
3125   };
3126
3127   static int ep_active_bomb[] =
3128   {
3129     EL_DYNAMITE_ACTIVE,
3130     EL_DYNABOMB_PLAYER_1_ACTIVE,
3131     EL_DYNABOMB_PLAYER_2_ACTIVE,
3132     EL_DYNABOMB_PLAYER_3_ACTIVE,
3133     EL_DYNABOMB_PLAYER_4_ACTIVE,
3134     EL_SP_DISK_RED_ACTIVE,
3135     -1
3136   };
3137
3138   static int ep_inactive[] =
3139   {
3140     EL_EMPTY,
3141     EL_SAND,
3142     EL_WALL,
3143     EL_BD_WALL,
3144     EL_WALL_SLIPPERY,
3145     EL_STEELWALL,
3146     EL_AMOEBA_DEAD,
3147     EL_QUICKSAND_EMPTY,
3148     EL_STONEBLOCK,
3149     EL_ROBOT_WHEEL,
3150     EL_KEY_1,
3151     EL_KEY_2,
3152     EL_KEY_3,
3153     EL_KEY_4,
3154     EL_EM_KEY_1,
3155     EL_EM_KEY_2,
3156     EL_EM_KEY_3,
3157     EL_EM_KEY_4,
3158     EL_EMC_KEY_5,
3159     EL_EMC_KEY_6,
3160     EL_EMC_KEY_7,
3161     EL_EMC_KEY_8,
3162     EL_GATE_1,
3163     EL_GATE_2,
3164     EL_GATE_3,
3165     EL_GATE_4,
3166     EL_GATE_1_GRAY,
3167     EL_GATE_2_GRAY,
3168     EL_GATE_3_GRAY,
3169     EL_GATE_4_GRAY,
3170     EL_EM_GATE_1,
3171     EL_EM_GATE_2,
3172     EL_EM_GATE_3,
3173     EL_EM_GATE_4,
3174     EL_EM_GATE_1_GRAY,
3175     EL_EM_GATE_2_GRAY,
3176     EL_EM_GATE_3_GRAY,
3177     EL_EM_GATE_4_GRAY,
3178     EL_EMC_GATE_5,
3179     EL_EMC_GATE_6,
3180     EL_EMC_GATE_7,
3181     EL_EMC_GATE_8,
3182     EL_EMC_GATE_5_GRAY,
3183     EL_EMC_GATE_6_GRAY,
3184     EL_EMC_GATE_7_GRAY,
3185     EL_EMC_GATE_8_GRAY,
3186     EL_DYNAMITE,
3187     EL_INVISIBLE_STEELWALL,
3188     EL_INVISIBLE_WALL,
3189     EL_INVISIBLE_SAND,
3190     EL_LAMP,
3191     EL_LAMP_ACTIVE,
3192     EL_WALL_EMERALD,
3193     EL_WALL_DIAMOND,
3194     EL_WALL_BD_DIAMOND,
3195     EL_WALL_EMERALD_YELLOW,
3196     EL_DYNABOMB_INCREASE_NUMBER,
3197     EL_DYNABOMB_INCREASE_SIZE,
3198     EL_DYNABOMB_INCREASE_POWER,
3199 #if 0
3200     EL_SOKOBAN_OBJECT,
3201 #endif
3202     EL_SOKOBAN_FIELD_EMPTY,
3203     EL_SOKOBAN_FIELD_FULL,
3204     EL_WALL_EMERALD_RED,
3205     EL_WALL_EMERALD_PURPLE,
3206     EL_ACID_POOL_TOPLEFT,
3207     EL_ACID_POOL_TOPRIGHT,
3208     EL_ACID_POOL_BOTTOMLEFT,
3209     EL_ACID_POOL_BOTTOM,
3210     EL_ACID_POOL_BOTTOMRIGHT,
3211     EL_MAGIC_WALL,
3212     EL_MAGIC_WALL_DEAD,
3213     EL_BD_MAGIC_WALL,
3214     EL_BD_MAGIC_WALL_DEAD,
3215     EL_AMOEBA_TO_DIAMOND,
3216     EL_BLOCKED,
3217     EL_SP_EMPTY,
3218     EL_SP_BASE,
3219     EL_SP_PORT_RIGHT,
3220     EL_SP_PORT_DOWN,
3221     EL_SP_PORT_LEFT,
3222     EL_SP_PORT_UP,
3223     EL_SP_GRAVITY_PORT_RIGHT,
3224     EL_SP_GRAVITY_PORT_DOWN,
3225     EL_SP_GRAVITY_PORT_LEFT,
3226     EL_SP_GRAVITY_PORT_UP,
3227     EL_SP_PORT_HORIZONTAL,
3228     EL_SP_PORT_VERTICAL,
3229     EL_SP_PORT_ANY,
3230     EL_SP_DISK_RED,
3231 #if 0
3232     EL_SP_DISK_YELLOW,
3233 #endif
3234     EL_SP_CHIP_SINGLE,
3235     EL_SP_CHIP_LEFT,
3236     EL_SP_CHIP_RIGHT,
3237     EL_SP_CHIP_TOP,
3238     EL_SP_CHIP_BOTTOM,
3239     EL_SP_HARDWARE_GRAY,
3240     EL_SP_HARDWARE_GREEN,
3241     EL_SP_HARDWARE_BLUE,
3242     EL_SP_HARDWARE_RED,
3243     EL_SP_HARDWARE_YELLOW,
3244     EL_SP_HARDWARE_BASE_1,
3245     EL_SP_HARDWARE_BASE_2,
3246     EL_SP_HARDWARE_BASE_3,
3247     EL_SP_HARDWARE_BASE_4,
3248     EL_SP_HARDWARE_BASE_5,
3249     EL_SP_HARDWARE_BASE_6,
3250     EL_SP_GRAVITY_ON_PORT_LEFT,
3251     EL_SP_GRAVITY_ON_PORT_RIGHT,
3252     EL_SP_GRAVITY_ON_PORT_UP,
3253     EL_SP_GRAVITY_ON_PORT_DOWN,
3254     EL_SP_GRAVITY_OFF_PORT_LEFT,
3255     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3256     EL_SP_GRAVITY_OFF_PORT_UP,
3257     EL_SP_GRAVITY_OFF_PORT_DOWN,
3258     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3259     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3260     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3261     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3262     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3263     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3264     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3265     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3266     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3267     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3268     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3269     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3270     EL_SIGN_EXCLAMATION,
3271     EL_SIGN_RADIOACTIVITY,
3272     EL_SIGN_STOP,
3273     EL_SIGN_WHEELCHAIR,
3274     EL_SIGN_PARKING,
3275     EL_SIGN_ONEWAY,
3276     EL_SIGN_HEART,
3277     EL_SIGN_TRIANGLE,
3278     EL_SIGN_ROUND,
3279     EL_SIGN_EXIT,
3280     EL_SIGN_YINYANG,
3281     EL_SIGN_OTHER,
3282     EL_STEELWALL_SLIPPERY,
3283     EL_EMC_STEELWALL_1,
3284     EL_EMC_STEELWALL_2,
3285     EL_EMC_STEELWALL_3,
3286     EL_EMC_STEELWALL_4,
3287     EL_EMC_WALL_SLIPPERY_1,
3288     EL_EMC_WALL_SLIPPERY_2,
3289     EL_EMC_WALL_SLIPPERY_3,
3290     EL_EMC_WALL_SLIPPERY_4,
3291     EL_EMC_WALL_1,
3292     EL_EMC_WALL_2,
3293     EL_EMC_WALL_3,
3294     EL_EMC_WALL_4,
3295     EL_EMC_WALL_5,
3296     EL_EMC_WALL_6,
3297     EL_EMC_WALL_7,
3298     EL_EMC_WALL_8,
3299     EL_EMC_WALL_9,
3300     EL_EMC_WALL_10,
3301     EL_EMC_WALL_11,
3302     EL_EMC_WALL_12,
3303     EL_EMC_WALL_13,
3304     EL_EMC_WALL_14,
3305     EL_EMC_WALL_15,
3306     EL_EMC_WALL_16,
3307     -1
3308   };
3309
3310   static int ep_em_slippery_wall[] =
3311   {
3312     -1
3313   };
3314
3315   static int ep_gfx_crumbled[] =
3316   {
3317     EL_SAND,
3318     EL_LANDMINE,
3319     EL_TRAP,
3320     EL_TRAP_ACTIVE,
3321     -1
3322   };
3323
3324   static struct
3325   {
3326     int *elements;
3327     int property;
3328   } element_properties[] =
3329   {
3330     { ep_diggable,              EP_DIGGABLE             },
3331     { ep_collectible_only,      EP_COLLECTIBLE_ONLY     },
3332     { ep_dont_run_into,         EP_DONT_RUN_INTO        },
3333     { ep_dont_collide_with,     EP_DONT_COLLIDE_WITH    },
3334     { ep_dont_touch,            EP_DONT_TOUCH           },
3335     { ep_indestructible,        EP_INDESTRUCTIBLE       },
3336     { ep_slippery,              EP_SLIPPERY             },
3337     { ep_can_change,            EP_CAN_CHANGE           },
3338     { ep_can_move,              EP_CAN_MOVE             },
3339     { ep_can_fall,              EP_CAN_FALL             },
3340     { ep_can_smash_player,      EP_CAN_SMASH_PLAYER     },
3341     { ep_can_smash_enemies,     EP_CAN_SMASH_ENEMIES    },
3342     { ep_can_smash_everything,  EP_CAN_SMASH_EVERYTHING },
3343     { ep_explodes_by_fire,      EP_EXPLODES_BY_FIRE     },
3344     { ep_explodes_smashed,      EP_EXPLODES_SMASHED     },
3345     { ep_explodes_impact,       EP_EXPLODES_IMPACT      },
3346     { ep_walkable_over,         EP_WALKABLE_OVER        },
3347     { ep_walkable_inside,       EP_WALKABLE_INSIDE      },
3348     { ep_walkable_under,        EP_WALKABLE_UNDER       },
3349     { ep_passable_over,         EP_PASSABLE_OVER        },
3350     { ep_passable_inside,       EP_PASSABLE_INSIDE      },
3351     { ep_passable_under,        EP_PASSABLE_UNDER       },
3352     { ep_droppable,             EP_DROPPABLE            },
3353     { ep_explodes_1x1_old,      EP_EXPLODES_1X1_OLD     },
3354     { ep_pushable,              EP_PUSHABLE             },
3355     { ep_explodes_cross_old,    EP_EXPLODES_CROSS_OLD   },
3356     { ep_protected,             EP_PROTECTED            },
3357     { ep_throwable,             EP_THROWABLE            },
3358     { ep_can_explode,           EP_CAN_EXPLODE          },
3359     { ep_gravity_reachable,     EP_GRAVITY_REACHABLE    },
3360
3361     { ep_player,                EP_PLAYER               },
3362     { ep_can_pass_magic_wall,   EP_CAN_PASS_MAGIC_WALL  },
3363     { ep_switchable,            EP_SWITCHABLE           },
3364     { ep_bd_element,            EP_BD_ELEMENT           },
3365     { ep_sp_element,            EP_SP_ELEMENT           },
3366     { ep_sb_element,            EP_SB_ELEMENT           },
3367     { ep_gem,                   EP_GEM                  },
3368     { ep_food_dark_yamyam,      EP_FOOD_DARK_YAMYAM     },
3369     { ep_food_penguin,          EP_FOOD_PENGUIN         },
3370     { ep_food_pig,              EP_FOOD_PIG             },
3371     { ep_historic_wall,         EP_HISTORIC_WALL        },
3372     { ep_historic_solid,        EP_HISTORIC_SOLID       },
3373     { ep_classic_enemy,         EP_CLASSIC_ENEMY        },
3374     { ep_belt,                  EP_BELT                 },
3375     { ep_belt_active,           EP_BELT_ACTIVE          },
3376     { ep_belt_switch,           EP_BELT_SWITCH          },
3377     { ep_tube,                  EP_TUBE                 },
3378     { ep_keygate,               EP_KEYGATE              },
3379     { ep_amoeboid,              EP_AMOEBOID             },
3380     { ep_amoebalive,            EP_AMOEBALIVE           },
3381     { ep_has_content,           EP_HAS_CONTENT          },
3382     { ep_can_turn_each_move,    EP_CAN_TURN_EACH_MOVE   },
3383     { ep_can_grow,              EP_CAN_GROW             },
3384     { ep_active_bomb,           EP_ACTIVE_BOMB          },
3385     { ep_inactive,              EP_INACTIVE             },
3386
3387     { ep_em_slippery_wall,      EP_EM_SLIPPERY_WALL     },
3388
3389     { ep_gfx_crumbled,          EP_GFX_CRUMBLED         },
3390
3391     { NULL,                     -1                      }
3392   };
3393
3394   int i, j, k;
3395
3396   /* always start with reliable default values (element has no properties) */
3397   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3398     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3399       SET_PROPERTY(i, j, FALSE);
3400
3401   /* set all base element properties from above array definitions */
3402   for (i = 0; element_properties[i].elements != NULL; i++)
3403     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3404       SET_PROPERTY((element_properties[i].elements)[j],
3405                    element_properties[i].property, TRUE);
3406
3407   /* copy properties to some elements that are only stored in level file */
3408   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3409     for (j = 0; copy_properties[j][0] != -1; j++)
3410       if (HAS_PROPERTY(copy_properties[j][0], i))
3411         for (k = 1; k <= 4; k++)
3412           SET_PROPERTY(copy_properties[j][k], i, TRUE);
3413 }
3414
3415 void InitElementPropertiesEngine(int engine_version)
3416 {
3417   static int no_wall_properties[] =
3418   {
3419     EP_DIGGABLE,
3420     EP_COLLECTIBLE_ONLY,
3421     EP_DONT_RUN_INTO,
3422     EP_DONT_COLLIDE_WITH,
3423     EP_CAN_MOVE,
3424     EP_CAN_FALL,
3425     EP_CAN_SMASH_PLAYER,
3426     EP_CAN_SMASH_ENEMIES,
3427     EP_CAN_SMASH_EVERYTHING,
3428     EP_PUSHABLE,
3429
3430     EP_PLAYER,
3431     EP_GEM,
3432     EP_FOOD_DARK_YAMYAM,
3433     EP_FOOD_PENGUIN,
3434     EP_BELT,
3435     EP_BELT_ACTIVE,
3436     EP_TUBE,
3437     EP_AMOEBOID,
3438     EP_AMOEBALIVE,
3439     EP_ACTIVE_BOMB,
3440
3441     EP_ACCESSIBLE,
3442
3443     -1
3444   };
3445
3446   int i, j;
3447
3448   /* important: after initialization in InitElementPropertiesStatic(), the
3449      elements are not again initialized to a default value; therefore all
3450      changes have to make sure that they leave the element with a defined
3451      property (which means that conditional property changes must be set to
3452      a reliable default value before) */
3453
3454   /* set all special, combined or engine dependent element properties */
3455   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3456   {
3457     /* ---------- INACTIVE ------------------------------------------------- */
3458     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3459
3460     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3461     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3462                                   IS_WALKABLE_INSIDE(i) ||
3463                                   IS_WALKABLE_UNDER(i)));
3464
3465     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3466                                   IS_PASSABLE_INSIDE(i) ||
3467                                   IS_PASSABLE_UNDER(i)));
3468
3469     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3470                                          IS_PASSABLE_OVER(i)));
3471
3472     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3473                                            IS_PASSABLE_INSIDE(i)));
3474
3475     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3476                                           IS_PASSABLE_UNDER(i)));
3477
3478     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3479                                     IS_PASSABLE(i)));
3480
3481     /* ---------- COLLECTIBLE ---------------------------------------------- */
3482     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3483                                      IS_DROPPABLE(i) ||
3484                                      IS_THROWABLE(i)));
3485
3486     /* ---------- SNAPPABLE ------------------------------------------------ */
3487     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3488                                    IS_COLLECTIBLE(i) ||
3489                                    IS_SWITCHABLE(i) ||
3490                                    i == EL_BD_ROCK));
3491
3492     /* ---------- WALL ----------------------------------------------------- */
3493     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3494
3495     for (j = 0; no_wall_properties[j] != -1; j++)
3496       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3497           i >= EL_FIRST_RUNTIME_UNREAL)
3498         SET_PROPERTY(i, EP_WALL, FALSE);
3499
3500     if (IS_HISTORIC_WALL(i))
3501       SET_PROPERTY(i, EP_WALL, TRUE);
3502
3503     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3504     if (engine_version < VERSION_IDENT(2,2,0,0))
3505       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3506     else
3507       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3508                                              !IS_DIGGABLE(i) &&
3509                                              !IS_COLLECTIBLE(i)));
3510
3511     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3512
3513     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3514       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3515     else
3516       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3517                                             IS_INDESTRUCTIBLE(i)));
3518
3519     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3520     if (i == EL_FLAMES)
3521       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3522     else if (engine_version < VERSION_IDENT(2,2,0,0))
3523       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3524     else
3525       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3526                                            (!IS_WALKABLE(i) ||
3527                                             IS_PROTECTED(i))));
3528
3529     if (IS_CUSTOM_ELEMENT(i))
3530     {
3531       /* these are additional properties which are initially false when set */
3532
3533       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3534       if (DONT_TOUCH(i))
3535         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3536       if (DONT_COLLIDE_WITH(i))
3537         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3538
3539       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3540       if (CAN_SMASH_EVERYTHING(i))
3541         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3542       if (CAN_SMASH_ENEMIES(i))
3543         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3544     }
3545
3546     /* ---------- CAN_SMASH ------------------------------------------------ */
3547     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3548                                    CAN_SMASH_ENEMIES(i) ||
3549                                    CAN_SMASH_EVERYTHING(i)));
3550
3551     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3552     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3553                                              EXPLODES_BY_FIRE(i)));
3554
3555     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3556     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3557                                              EXPLODES_SMASHED(i)));
3558
3559     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3560     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3561                                             EXPLODES_IMPACT(i)));
3562
3563     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3564     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3565
3566     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3567     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3568                                                   i == EL_BLACK_ORB));
3569
3570     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3571     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3572                                               CAN_MOVE(i) ||
3573                                               IS_CUSTOM_ELEMENT(i)));
3574
3575     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3576     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3577                                                  i == EL_SP_ELECTRON));
3578
3579     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3580     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3581       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3582                    getMoveIntoAcidProperty(&level, i));
3583
3584     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3585     if (MAYBE_DONT_COLLIDE_WITH(i))
3586       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3587                    getDontCollideWithProperty(&level, i));
3588
3589     /* ---------- SP_PORT -------------------------------------------------- */
3590     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3591                                  IS_PASSABLE_INSIDE(i)));
3592
3593     /* ---------- CAN_CHANGE ----------------------------------------------- */
3594     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3595     for (j = 0; j < element_info[i].num_change_pages; j++)
3596       if (element_info[i].change_page[j].can_change)
3597         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3598
3599     /* ---------- HAS_ACTION ----------------------------------------------- */
3600     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
3601     for (j = 0; j < element_info[i].num_change_pages; j++)
3602       if (element_info[i].change_page[j].has_action)
3603         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3604
3605     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3606     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3607                                                   HAS_ACTION(i)));
3608
3609     /* ---------- GFX_CRUMBLED --------------------------------------------- */
3610 #if 1
3611     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3612                  element_info[i].crumbled[ACTION_DEFAULT] !=
3613                  element_info[i].graphic[ACTION_DEFAULT]);
3614 #else
3615     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3616     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3617                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3618 #endif
3619   }
3620
3621   /* dynamically adjust element properties according to game engine version */
3622   {
3623     static int ep_em_slippery_wall[] =
3624     {
3625       EL_STEELWALL,
3626       EL_WALL,
3627       EL_EXPANDABLE_WALL,
3628       EL_EXPANDABLE_WALL_HORIZONTAL,
3629       EL_EXPANDABLE_WALL_VERTICAL,
3630       EL_EXPANDABLE_WALL_ANY,
3631       -1
3632     };
3633
3634     /* special EM style gems behaviour */
3635     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3636       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3637                    level.em_slippery_gems);
3638
3639     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3640     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3641                  (level.em_slippery_gems &&
3642                   engine_version > VERSION_IDENT(2,0,1,0)));
3643   }
3644
3645   /* set default push delay values (corrected since version 3.0.7-1) */
3646   if (engine_version < VERSION_IDENT(3,0,7,1))
3647   {
3648     game.default_push_delay_fixed = 2;
3649     game.default_push_delay_random = 8;
3650   }
3651   else
3652   {
3653     game.default_push_delay_fixed = 8;
3654     game.default_push_delay_random = 8;
3655   }
3656
3657   /* set uninitialized push delay values of custom elements in older levels */
3658   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3659   {
3660     int element = EL_CUSTOM_START + i;
3661
3662     if (element_info[element].push_delay_fixed == -1)
3663       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3664     if (element_info[element].push_delay_random == -1)
3665       element_info[element].push_delay_random = game.default_push_delay_random;
3666   }
3667
3668   /* set some other uninitialized values of custom elements in older levels */
3669   if (engine_version < VERSION_IDENT(3,1,0,0))
3670   {
3671     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3672     {
3673       int element = EL_CUSTOM_START + i;
3674
3675       element_info[element].access_direction = MV_ALL_DIRECTIONS;
3676
3677       element_info[element].explosion_delay = 17;
3678       element_info[element].ignition_delay = 8;
3679     }
3680   }
3681
3682 #if 0
3683   /* set element properties that were handled incorrectly in older levels */
3684   if (engine_version < VERSION_IDENT(3,1,0,0))
3685   {
3686     SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3687     SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3688   }
3689 #endif
3690
3691   /* this is needed because some graphics depend on element properties */
3692   if (game_status == GAME_MODE_PLAYING)
3693     InitElementGraphicInfo();
3694 }
3695
3696 static void InitGlobal()
3697 {
3698   int i;
3699
3700   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3701   {
3702     /* check if element_name_info entry defined for each element in "main.h" */
3703     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3704       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3705
3706     element_info[i].token_name = element_name_info[i].token_name;
3707     element_info[i].class_name = element_name_info[i].class_name;
3708     element_info[i].editor_description=element_name_info[i].editor_description;
3709   }
3710
3711   global.autoplay_leveldir = NULL;
3712   global.convert_leveldir = NULL;
3713
3714   global.frames_per_second = 0;
3715   global.fps_slowdown = FALSE;
3716   global.fps_slowdown_factor = 1;
3717 }
3718
3719 void Execute_Command(char *command)
3720 {
3721   int i;
3722
3723   if (strcmp(command, "print graphicsinfo.conf") == 0)
3724   {
3725     printf("# You can configure additional/alternative image files here.\n");
3726     printf("# (The entries below are default and therefore commented out.)\n");
3727     printf("\n");
3728     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3729     printf("\n");
3730     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3731     printf("\n");
3732
3733     for (i = 0; image_config[i].token != NULL; i++)
3734       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3735                                               image_config[i].value));
3736
3737     exit(0);
3738   }
3739   else if (strcmp(command, "print soundsinfo.conf") == 0)
3740   {
3741     printf("# You can configure additional/alternative sound files here.\n");
3742     printf("# (The entries below are default and therefore commented out.)\n");
3743     printf("\n");
3744     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3745     printf("\n");
3746     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3747     printf("\n");
3748
3749     for (i = 0; sound_config[i].token != NULL; i++)
3750       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3751                                               sound_config[i].value));
3752
3753     exit(0);
3754   }
3755   else if (strcmp(command, "print musicinfo.conf") == 0)
3756   {
3757     printf("# You can configure additional/alternative music files here.\n");
3758     printf("# (The entries below are default and therefore commented out.)\n");
3759     printf("\n");
3760     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3761     printf("\n");
3762     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3763     printf("\n");
3764
3765     for (i = 0; music_config[i].token != NULL; i++)
3766       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
3767                                               music_config[i].value));
3768
3769     exit(0);
3770   }
3771   else if (strcmp(command, "print editorsetup.conf") == 0)
3772   {
3773     printf("# You can configure your personal editor element list here.\n");
3774     printf("# (The entries below are default and therefore commented out.)\n");
3775     printf("\n");
3776
3777     PrintEditorElementList();
3778
3779     exit(0);
3780   }
3781   else if (strcmp(command, "print helpanim.conf") == 0)
3782   {
3783     printf("# You can configure different element help animations here.\n");
3784     printf("# (The entries below are default and therefore commented out.)\n");
3785     printf("\n");
3786
3787     for (i = 0; helpanim_config[i].token != NULL; i++)
3788     {
3789       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
3790                                               helpanim_config[i].value));
3791
3792       if (strcmp(helpanim_config[i].token, "end") == 0)
3793         printf("#\n");
3794     }
3795
3796     exit(0);
3797   }
3798   else if (strcmp(command, "print helptext.conf") == 0)
3799   {
3800     printf("# You can configure different element help text here.\n");
3801     printf("# (The entries below are default and therefore commented out.)\n");
3802     printf("\n");
3803
3804     for (i = 0; helptext_config[i].token != NULL; i++)
3805       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
3806                                               helptext_config[i].value));
3807
3808     exit(0);
3809   }
3810   else if (strncmp(command, "dump level ", 11) == 0)
3811   {
3812     char *filename = &command[11];
3813
3814     if (!fileExists(filename))
3815       Error(ERR_EXIT, "cannot open file '%s'", filename);
3816
3817     LoadLevelFromFilename(&level, filename);
3818     DumpLevel(&level);
3819
3820     exit(0);
3821   }
3822   else if (strncmp(command, "dump tape ", 10) == 0)
3823   {
3824     char *filename = &command[10];
3825
3826     if (!fileExists(filename))
3827       Error(ERR_EXIT, "cannot open file '%s'", filename);
3828
3829     LoadTapeFromFilename(filename);
3830     DumpTape(&tape);
3831
3832     exit(0);
3833   }
3834   else if (strncmp(command, "autoplay ", 9) == 0)
3835   {
3836     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
3837
3838     while (*str_ptr != '\0')                    /* continue parsing string */
3839     {
3840       /* cut leading whitespace from string, replace it by string terminator */
3841       while (*str_ptr == ' ' || *str_ptr == '\t')
3842         *str_ptr++ = '\0';
3843
3844       if (*str_ptr == '\0')                     /* end of string reached */
3845         break;
3846
3847       if (global.autoplay_leveldir == NULL)     /* read level set string */
3848       {
3849         global.autoplay_leveldir = str_ptr;
3850         global.autoplay_all = TRUE;             /* default: play all tapes */
3851
3852         for (i = 0; i < MAX_TAPES_PER_SET; i++)
3853           global.autoplay_level[i] = FALSE;
3854       }
3855       else                                      /* read level number string */
3856       {
3857         int level_nr = atoi(str_ptr);           /* get level_nr value */
3858
3859         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
3860           global.autoplay_level[level_nr] = TRUE;
3861
3862         global.autoplay_all = FALSE;
3863       }
3864
3865       /* advance string pointer to the next whitespace (or end of string) */
3866       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
3867         str_ptr++;
3868     }
3869   }
3870   else if (strncmp(command, "convert ", 8) == 0)
3871   {
3872     char *str_copy = getStringCopy(&command[8]);
3873     char *str_ptr = strchr(str_copy, ' ');
3874
3875     global.convert_leveldir = str_copy;
3876     global.convert_level_nr = -1;
3877
3878     if (str_ptr != NULL)                        /* level number follows */
3879     {
3880       *str_ptr++ = '\0';                        /* terminate leveldir string */
3881       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
3882     }
3883   }
3884   else
3885   {
3886     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
3887   }
3888 }
3889
3890 static void InitSetup()
3891 {
3892   LoadSetup();                                  /* global setup info */
3893
3894   /* set some options from setup file */
3895
3896   if (setup.options.verbose)
3897     options.verbose = TRUE;
3898 }
3899
3900 static void InitGameInfo()
3901 {
3902   game.restart_level = FALSE;
3903 }
3904
3905 static void InitPlayerInfo()
3906 {
3907   int i;
3908
3909   /* choose default local player */
3910   local_player = &stored_player[0];
3911
3912   for (i = 0; i < MAX_PLAYERS; i++)
3913     stored_player[i].connected = FALSE;
3914
3915   local_player->connected = TRUE;
3916 }
3917
3918 static void InitArtworkInfo()
3919 {
3920   LoadArtworkInfo();
3921 }
3922
3923 static char *get_string_in_brackets(char *string)
3924 {
3925   char *string_in_brackets = checked_malloc(strlen(string) + 3);
3926
3927   sprintf(string_in_brackets, "[%s]", string);
3928
3929   return string_in_brackets;
3930 }
3931
3932 static char *get_level_id_suffix(int id_nr)
3933 {
3934   char *id_suffix = checked_malloc(1 + 3 + 1);
3935
3936   if (id_nr < 0 || id_nr > 999)
3937     id_nr = 0;
3938
3939   sprintf(id_suffix, ".%03d", id_nr);
3940
3941   return id_suffix;
3942 }
3943
3944 #if 0
3945 static char *get_element_class_token(int element)
3946 {
3947   char *element_class_name = element_info[element].class_name;
3948   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
3949
3950   sprintf(element_class_token, "[%s]", element_class_name);
3951
3952   return element_class_token;
3953 }
3954
3955 static char *get_action_class_token(int action)
3956 {
3957   char *action_class_name = &element_action_info[action].suffix[1];
3958   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
3959
3960   sprintf(action_class_token, "[%s]", action_class_name);
3961
3962   return action_class_token;
3963 }
3964 #endif
3965
3966 static void InitArtworkConfig()
3967 {
3968   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
3969   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
3970   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
3971   static char *action_id_suffix[NUM_ACTIONS + 1];
3972   static char *direction_id_suffix[NUM_DIRECTIONS + 1];
3973   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
3974   static char *level_id_suffix[MAX_LEVELS + 1];
3975   static char *dummy[1] = { NULL };
3976   static char *ignore_generic_tokens[] =
3977   {
3978     "name",
3979     "sort_priority",
3980     NULL
3981   };
3982   static char **ignore_image_tokens;
3983   static char **ignore_sound_tokens;
3984   static char **ignore_music_tokens;
3985   int num_ignore_generic_tokens;
3986   int num_ignore_image_tokens;
3987   int num_ignore_sound_tokens;
3988   int num_ignore_music_tokens;
3989   int i;
3990
3991   /* dynamically determine list of generic tokens to be ignored */
3992   num_ignore_generic_tokens = 0;
3993   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
3994     num_ignore_generic_tokens++;
3995
3996   /* dynamically determine list of image tokens to be ignored */
3997   num_ignore_image_tokens = num_ignore_generic_tokens;
3998   for (i = 0; image_config_vars[i].token != NULL; i++)
3999     num_ignore_image_tokens++;
4000   ignore_image_tokens =
4001     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4002   for (i = 0; i < num_ignore_generic_tokens; i++)
4003     ignore_image_tokens[i] = ignore_generic_tokens[i];
4004   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4005     ignore_image_tokens[num_ignore_generic_tokens + i] =
4006       image_config_vars[i].token;
4007   ignore_image_tokens[num_ignore_image_tokens] = NULL;
4008
4009   /* dynamically determine list of sound tokens to be ignored */
4010   num_ignore_sound_tokens = num_ignore_generic_tokens;
4011   ignore_sound_tokens =
4012     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4013   for (i = 0; i < num_ignore_generic_tokens; i++)
4014     ignore_sound_tokens[i] = ignore_generic_tokens[i];
4015   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4016
4017   /* dynamically determine list of music tokens to be ignored */
4018   num_ignore_music_tokens = num_ignore_generic_tokens;
4019   ignore_music_tokens =
4020     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4021   for (i = 0; i < num_ignore_generic_tokens; i++)
4022     ignore_music_tokens[i] = ignore_generic_tokens[i];
4023   ignore_music_tokens[num_ignore_music_tokens] = NULL;
4024
4025   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4026     image_id_prefix[i] = element_info[i].token_name;
4027   for (i = 0; i < NUM_FONTS; i++)
4028     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4029   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4030
4031   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4032     sound_id_prefix[i] = element_info[i].token_name;
4033   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4034     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4035       get_string_in_brackets(element_info[i].class_name);
4036   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4037
4038   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4039     music_id_prefix[i] = music_prefix_info[i].prefix;
4040   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4041
4042   for (i = 0; i < NUM_ACTIONS; i++)
4043     action_id_suffix[i] = element_action_info[i].suffix;
4044   action_id_suffix[NUM_ACTIONS] = NULL;
4045
4046   for (i = 0; i < NUM_DIRECTIONS; i++)
4047     direction_id_suffix[i] = element_direction_info[i].suffix;
4048   direction_id_suffix[NUM_DIRECTIONS] = NULL;
4049
4050   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4051     special_id_suffix[i] = special_suffix_info[i].suffix;
4052   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4053
4054   for (i = 0; i < MAX_LEVELS; i++)
4055     level_id_suffix[i] = get_level_id_suffix(i);
4056   level_id_suffix[MAX_LEVELS] = NULL;
4057
4058   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4059                 image_id_prefix, action_id_suffix, direction_id_suffix,
4060                 special_id_suffix, ignore_image_tokens);
4061   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4062                 sound_id_prefix, action_id_suffix, dummy,
4063                 special_id_suffix, ignore_sound_tokens);
4064   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4065                 music_id_prefix, special_id_suffix, level_id_suffix,
4066                 dummy, ignore_music_tokens);
4067 }
4068
4069 static void InitMixer()
4070 {
4071   OpenAudio();
4072   StartMixer();
4073 }
4074
4075 void InitGfx()
4076 {
4077   char *filename_font_initial = NULL;
4078   Bitmap *bitmap_font_initial = NULL;
4079   int i, j;
4080
4081   /* determine settings for initial font (for displaying startup messages) */
4082   for (i = 0; image_config[i].token != NULL; i++)
4083   {
4084     for (j = 0; j < NUM_INITIAL_FONTS; j++)
4085     {
4086       char font_token[128];
4087       int len_font_token;
4088
4089       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4090       len_font_token = strlen(font_token);
4091
4092       if (strcmp(image_config[i].token, font_token) == 0)
4093         filename_font_initial = image_config[i].value;
4094       else if (strlen(image_config[i].token) > len_font_token &&
4095                strncmp(image_config[i].token, font_token, len_font_token) == 0)
4096       {
4097         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4098           font_initial[j].src_x = atoi(image_config[i].value);
4099         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4100           font_initial[j].src_y = atoi(image_config[i].value);
4101         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4102           font_initial[j].width = atoi(image_config[i].value);
4103         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4104           font_initial[j].height = atoi(image_config[i].value);
4105       }
4106     }
4107   }
4108
4109   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4110   {
4111     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4112     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4113   }
4114
4115   if (filename_font_initial == NULL)    /* should not happen */
4116     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4117
4118   /* create additional image buffers for double-buffering */
4119   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4120   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4121
4122   /* initialize screen properties */
4123   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4124                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4125                    bitmap_db_field);
4126   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4127   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4128   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4129
4130   bitmap_font_initial = LoadCustomImage(filename_font_initial);
4131
4132   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4133     font_initial[j].bitmap = bitmap_font_initial;
4134
4135   InitFontGraphicInfo();
4136
4137   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4138   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4139
4140   DrawInitText("Loading graphics:", 120, FC_GREEN);
4141 }
4142
4143 void InitGfxBackground()
4144 {
4145   int x, y;
4146
4147   drawto = backbuffer;
4148   fieldbuffer = bitmap_db_field;
4149   SetDrawtoField(DRAW_BACKBUFFER);
4150
4151   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4152              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4153   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4154   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4155
4156   for (x = 0; x < MAX_BUF_XSIZE; x++)
4157     for (y = 0; y < MAX_BUF_YSIZE; y++)
4158       redraw[x][y] = 0;
4159   redraw_tiles = 0;
4160   redraw_mask = REDRAW_ALL;
4161 }
4162
4163 static void InitLevelInfo()
4164 {
4165   LoadLevelInfo();                              /* global level info */
4166   LoadLevelSetup_LastSeries();                  /* last played series info */
4167   LoadLevelSetup_SeriesInfo();                  /* last played level info */
4168 }
4169
4170 void InitLevelArtworkInfo()
4171 {
4172   LoadLevelArtworkInfo();
4173 }
4174
4175 static void InitImages()
4176 {
4177   setLevelArtworkDir(artwork.gfx_first);
4178
4179 #if 0
4180   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4181          leveldir_current->identifier,
4182          artwork.gfx_current_identifier,
4183          artwork.gfx_current->identifier,
4184          leveldir_current->graphics_set,
4185          leveldir_current->graphics_path);
4186 #endif
4187
4188   ReloadCustomImages();
4189
4190   LoadCustomElementDescriptions();
4191   LoadSpecialMenuDesignSettings();
4192
4193   ReinitializeGraphics();
4194 }
4195
4196 static void InitSound(char *identifier)
4197 {
4198   if (identifier == NULL)
4199     identifier = artwork.snd_current->identifier;
4200
4201   /* set artwork path to send it to the sound server process */
4202   setLevelArtworkDir(artwork.snd_first);
4203
4204   InitReloadCustomSounds(identifier);
4205   ReinitializeSounds();
4206 }
4207
4208 static void InitMusic(char *identifier)
4209 {
4210   if (identifier == NULL)
4211     identifier = artwork.mus_current->identifier;
4212
4213   /* set artwork path to send it to the sound server process */
4214   setLevelArtworkDir(artwork.mus_first);
4215
4216   InitReloadCustomMusic(identifier);
4217   ReinitializeMusic();
4218 }
4219
4220 void InitNetworkServer()
4221 {
4222 #if defined(NETWORK_AVALIABLE)
4223   int nr_wanted;
4224 #endif
4225
4226   if (!options.network)
4227     return;
4228
4229 #if defined(NETWORK_AVALIABLE)
4230   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4231
4232   if (!ConnectToServer(options.server_host, options.server_port))
4233     Error(ERR_EXIT, "cannot connect to network game server");
4234
4235   SendToServer_PlayerName(setup.player_name);
4236   SendToServer_ProtocolVersion();
4237
4238   if (nr_wanted)
4239     SendToServer_NrWanted(nr_wanted);
4240 #endif
4241 }
4242
4243 static char *getNewArtworkIdentifier(int type)
4244 {
4245   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4246   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4247   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4248   static boolean initialized[3] = { FALSE, FALSE, FALSE };
4249   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4250   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4251   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4252   char *leveldir_identifier = leveldir_current->identifier;
4253 #if 1
4254   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4255   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4256 #else
4257   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4258 #endif
4259   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4260   char *artwork_current_identifier;
4261   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
4262
4263   /* leveldir_current may be invalid (level group, parent link) */
4264   if (!validLevelSeries(leveldir_current))
4265     return NULL;
4266
4267   /* 1st step: determine artwork set to be activated in descending order:
4268      --------------------------------------------------------------------
4269      1. setup artwork (when configured to override everything else)
4270      2. artwork set configured in "levelinfo.conf" of current level set
4271         (artwork in level directory will have priority when loading later)
4272      3. artwork in level directory (stored in artwork sub-directory)
4273      4. setup artwork (currently configured in setup menu) */
4274
4275   if (setup_override_artwork)
4276     artwork_current_identifier = setup_artwork_set;
4277   else if (leveldir_artwork_set != NULL)
4278     artwork_current_identifier = leveldir_artwork_set;
4279   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4280     artwork_current_identifier = leveldir_identifier;
4281   else
4282     artwork_current_identifier = setup_artwork_set;
4283
4284
4285   /* 2nd step: check if it is really needed to reload artwork set
4286      ------------------------------------------------------------ */
4287
4288 #if 0
4289   if (type == ARTWORK_TYPE_GRAPHICS)
4290     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4291            artwork_new_identifier,
4292            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4293            artwork_current_identifier,
4294            leveldir_current->graphics_set,
4295            leveldir_current->identifier);
4296 #endif
4297
4298   /* ---------- reload if level set and also artwork set has changed ------- */
4299   if (leveldir_current_identifier[type] != leveldir_identifier &&
4300       (last_has_level_artwork_set[type] || has_level_artwork_set))
4301     artwork_new_identifier = artwork_current_identifier;
4302
4303   leveldir_current_identifier[type] = leveldir_identifier;
4304   last_has_level_artwork_set[type] = has_level_artwork_set;
4305
4306 #if 0
4307   if (type == ARTWORK_TYPE_GRAPHICS)
4308     printf("::: 1: '%s'\n", artwork_new_identifier);
4309 #endif
4310
4311   /* ---------- reload if "override artwork" setting has changed ----------- */
4312   if (last_override_level_artwork[type] != setup_override_artwork)
4313     artwork_new_identifier = artwork_current_identifier;
4314
4315   last_override_level_artwork[type] = setup_override_artwork;
4316
4317 #if 0
4318   if (type == ARTWORK_TYPE_GRAPHICS)
4319     printf("::: 2: '%s'\n", artwork_new_identifier);
4320 #endif
4321
4322   /* ---------- reload if current artwork identifier has changed ----------- */
4323   if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4324              artwork_current_identifier) != 0)
4325     artwork_new_identifier = artwork_current_identifier;
4326
4327   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4328
4329 #if 0
4330   if (type == ARTWORK_TYPE_GRAPHICS)
4331     printf("::: 3: '%s'\n", artwork_new_identifier);
4332 #endif
4333
4334   /* ---------- do not reload directly after starting ---------------------- */
4335   if (!initialized[type])
4336     artwork_new_identifier = NULL;
4337
4338   initialized[type] = TRUE;
4339
4340 #if 0
4341   if (type == ARTWORK_TYPE_GRAPHICS)
4342     printf("::: 4: '%s'\n", artwork_new_identifier);
4343 #endif
4344
4345 #if 0
4346   if (type == ARTWORK_TYPE_GRAPHICS)
4347     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4348            artwork.gfx_current_identifier, artwork_current_identifier,
4349            artwork.gfx_current->identifier, leveldir_current->graphics_set,
4350            artwork_new_identifier);
4351 #endif
4352
4353   return artwork_new_identifier;
4354 }
4355
4356 void ReloadCustomArtwork(int force_reload)
4357 {
4358   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4359   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4360   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4361   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4362   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4363   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4364   boolean redraw_screen = FALSE;
4365
4366   if (gfx_new_identifier != NULL || force_reload_gfx)
4367   {
4368 #if 0
4369     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4370            artwork.gfx_current_identifier,
4371            gfx_new_identifier,
4372            artwork.gfx_current->identifier,
4373            leveldir_current->graphics_set);
4374 #endif
4375
4376     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4377
4378     InitImages();
4379
4380     redraw_screen = TRUE;
4381   }
4382
4383   if (snd_new_identifier != NULL || force_reload_snd)
4384   {
4385     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4386
4387     InitSound(snd_new_identifier);
4388
4389     redraw_screen = TRUE;
4390   }
4391
4392   if (mus_new_identifier != NULL || force_reload_mus)
4393   {
4394     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4395
4396     InitMusic(mus_new_identifier);
4397
4398     redraw_screen = TRUE;
4399   }
4400
4401   if (redraw_screen)
4402   {
4403     InitGfxBackground();
4404
4405     /* force redraw of (open or closed) door graphics */
4406     SetDoorState(DOOR_OPEN_ALL);
4407     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4408   }
4409 }
4410
4411 void KeyboardAutoRepeatOffUnlessAutoplay()
4412 {
4413   if (global.autoplay_leveldir == NULL)
4414     KeyboardAutoRepeatOff();
4415 }
4416
4417
4418 /* ========================================================================= */
4419 /* OpenAll()                                                                 */
4420 /* ========================================================================= */
4421
4422 void OpenAll()
4423 {
4424   InitGlobal();                 /* initialize some global variables */
4425
4426   if (options.execute_command)
4427     Execute_Command(options.execute_command);
4428
4429   if (options.serveronly)
4430   {
4431 #if defined(PLATFORM_UNIX)
4432     NetworkServer(options.server_port, options.serveronly);
4433 #else
4434     Error(ERR_WARN, "networking only supported in Unix version");
4435 #endif
4436
4437     exit(0);                    /* never reached, server loops forever */
4438   }
4439
4440   InitSetup();
4441
4442   InitGameInfo();
4443   InitPlayerInfo();
4444   InitArtworkInfo();            /* needed before loading gfx, sound & music */
4445   InitArtworkConfig();          /* needed before forking sound child process */
4446   InitMixer();
4447
4448   InitCounter();
4449
4450   InitRND(NEW_RANDOMIZE);
4451   InitSimpleRND(NEW_RANDOMIZE);
4452
4453   InitJoysticks();
4454
4455   InitVideoDisplay();
4456   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4457                   setup.fullscreen);
4458
4459   InitEventFilter(FilterMouseMotionEvents);
4460
4461   InitElementPropertiesStatic();
4462   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4463
4464   InitGfx();
4465
4466   InitLevelInfo();
4467   InitLevelArtworkInfo();
4468
4469   InitImages();                 /* needs to know current level directory */
4470   InitSound(NULL);              /* needs to know current level directory */
4471   InitMusic(NULL);              /* needs to know current level directory */
4472
4473   InitGfxBackground();
4474
4475   if (global.autoplay_leveldir)
4476   {
4477     AutoPlayTape();
4478     return;
4479   }
4480   else if (global.convert_leveldir)
4481   {
4482     ConvertLevels();
4483     return;
4484   }
4485
4486   game_status = GAME_MODE_MAIN;
4487
4488 #if 1
4489   em_open_all();
4490 #endif
4491
4492   DrawMainMenu();
4493
4494   InitNetworkServer();
4495 }
4496
4497 void CloseAllAndExit(int exit_value)
4498 {
4499   StopSounds();
4500   FreeAllSounds();
4501   FreeAllMusic();
4502   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4503
4504 #if 1
4505   em_close_all();
4506 #endif
4507
4508   FreeAllImages();
4509
4510 #if defined(TARGET_SDL)
4511   if (network_server)   /* terminate network server */
4512     SDL_KillThread(server_thread);
4513 #endif
4514
4515   CloseVideoDisplay();
4516   ClosePlatformDependentStuff();
4517
4518   exit(exit_value);
4519 }