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